home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / sun3.md / vmSun.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  108.8 KB  |  3,899 lines

  1. /* vmSunMach.c -
  2.  *
  3.  *         This file contains all hardware dependent routines for Sun2's and
  4.  *    Sun3's.  I will not attempt to explain the Sun mapping hardware in 
  5.  *    here.  See the Sun2 and Sun3 architecture manuals for details on
  6.  *    the mapping hardware.
  7.  *
  8.  * Copyright (C) 1985 Regents of the University of California
  9.  * All rights reserved.
  10.  */
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/sun3.md/vmSun.c,v 9.22 91/09/10 18:30:08 rab Exp $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16. #include <sprite.h>
  17. #include <vmSunConst.h>
  18. #include <machMon.h>
  19. #include <vm.h>
  20. #include <vmInt.h>
  21. #include <vmMach.h>
  22. #include <vmMachInt.h>
  23. #include <list.h>
  24. #include <mach.h>
  25. #include <proc.h>
  26. #include <sched.h>
  27. #include <stdlib.h>
  28. #include <sync.h>
  29. #include <sys.h>
  30. #include <dbg.h>
  31. #include <net.h>
  32. #include <stdio.h>
  33. #include <bstring.h>
  34.  
  35. #ifndef multiprocessor
  36.  
  37. #undef MASTER_LOCK
  38. #define MASTER_LOCK(mutexPtr)
  39. #undef MASTER_UNLOCK
  40. #define MASTER_UNLOCK(mutexPtr)
  41.  
  42. #else
  43.  
  44. /*
  45.  * The master lock to synchronize access to pmegs and context.
  46.  */
  47. static Sync_Semaphore vmMachMutex;
  48. static Sync_Semaphore volatile *vmMachMutexPtr = &vmMachMutex;
  49.  
  50. #endif
  51.  
  52. /*----------------------------------------------------------------------
  53.  * 
  54.  *             Hardware data structures
  55.  *
  56.  * Terminology: 
  57.  *    1) Physical page frame: A frame that contains one hardware page.
  58.  *    2) Virtual page frame:  A frame that contains VMMACH_CLUSTER_SIZE 
  59.  *                hardware pages.
  60.  *    3) Software segment: The segment structure used by the hardware
  61.  *                 independent VM module.
  62.  *    4) Hardware segment: A piece of a hardware context.
  63.  *
  64.  * A hardware context corresponds to a process's address space.  A context
  65.  * is made up of many equal sized hardware segments.  The 
  66.  * kernel is mapped into each hardware context so that the kernel has easy
  67.  * access to user data.  One context (context 0) is reserved for use by
  68.  * kernel processes.  The hardware contexts are defined by the array
  69.  * contextArray which contains an entry for each context.  Each entry 
  70.  * contains a pointer back to the process that is executing in the context 
  71.  * and an array which is an exact duplicate of the hardware segment map for
  72.  * the context.  The contexts are managed by keeping all contexts except for
  73.  * the system context in a list that is kept in LRU order.  Whenever a context 
  74.  * is needed the first context off of the list is used and the context is
  75.  * stolen from the current process that owns it if necessary.
  76.  *
  77.  * PMEGs are allocated to software segments in order to allow pages to be mapped
  78.  * into the segment's virtual address space. There are only a small number of 
  79.  * PMEGs (256) which have to be shared by all segments.  PMEGs that have
  80.  * been allocated to user segments can be stolen at any time.  PMEGs that have
  81.  * been allocated to the system segment cannot be taken away unless the system
  82.  * segment voluntarily gives it up.  In order to manage the PMEGs there are
  83.  * two data structures.  One is an array of PMEG info structures that contains
  84.  * one entry for each PMEG.  The other is an array stored with each software
  85.  * segment struct that contains the PMEGs that have been allocated to the
  86.  * software segment.  Each entry in the array of PMEG info structures
  87.  * contains enough information to remove the PMEG from its software segment.
  88.  * One of the fields in the PMEG info struct is the count of pages that have
  89.  * been validated in the PMEG.  This is used to determine when a PMEG is no
  90.  * longer being actively used.  
  91.  *
  92.  * There are two lists that are used to manage PMEGs.  The pmegFreeList 
  93.  * contains all PMEGs that are either not being used or contain no valid 
  94.  * page map entries; unused ones are inserted at the front of the list 
  95.  * and empty ones at the rear.  The pmegInuseList contains all PMEGs
  96.  * that are being actively used to map user segments and is managed as a FIFO.
  97.  * PMEGs that are being used to map tbe kernel's VAS do not appear on the 
  98.  * pmegInuseList. When a pmeg is needed to map a virtual address, first the
  99.  * free list is checked.  If it is not empty then the first PMEG is pulled 
  100.  * off of the list.  If it is empty then the first PMEG is pulled off of the
  101.  * inUse list.  If the PMEG  that is selected is being used (either actively 
  102.  * or inactively) then it is freed from the software segment that is using it.
  103.  * Once the PMEG is freed up then if it is being allocated for a user segment
  104.  * it is put onto the end of the pmegInuseList.
  105.  *
  106.  * Page frames are allocated to software segments even when there is
  107.  * no PMEG to map it in.  Thus when a PMEG that was mapping a page needs to
  108.  * be removed from the software segment that owns the page, the reference
  109.  * and modify bits stored in the PMEG for the page must be saved.  The
  110.  * array refModMap is used for this.  It contains one entry for each
  111.  * virtual page frame.  Its value for a page frame or'd with the bits stored
  112.  * in the PMEG (if any) comprise the referenced and modified bits for a 
  113.  * virtual page frame.
  114.  * 
  115.  * IMPORTANT SYNCHRONIZATION NOTE:
  116.  *
  117.  * The internal data structures in this file have to be protected by a
  118.  * master lock if this code is to be run on a multi-processor.  Since a
  119.  * process cannot start executing unless VmMach_SetupContext can be
  120.  * executed first, VmMach_SetupContext cannot context switch inside itself;
  121.  * otherwise a deadlock will occur.  However, VmMach_SetupContext mucks with
  122.  * contexts and PMEGS and therefore would have to be synchronized
  123.  * on a multi-processor.  A monitor lock cannot be used because it may force
  124.  * VmMach_SetupContext to be context switched.
  125.  *
  126.  * The routines in this file also muck with other per segment data structures.
  127.  * Access to these data structures is synchronized by our caller (the
  128.  * machine independent module).
  129.  *
  130.  *----------------------------------------------------------------------
  131.  */
  132.  
  133. /*
  134.  * Machine dependent flags for the flags field in the Vm_VirtAddr struct.
  135.  * We are only allowed to use the second byte of the flags.
  136.  *
  137.  *    USING_MAPPED_SEG        The parsed virtual address falls into
  138.  *                    the mapping segment.
  139.  */
  140. #define    USING_MAPPED_SEG    0x100
  141.  
  142. /*
  143.  * Macros to get to and from hardware segments and pages.
  144.  */
  145. #define PageToSeg(page) ((page) >> (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  146. #define SegToPage(seg) ((seg) << (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  147.  
  148. /*
  149.  * Convert from page to hardware segment, with correction for
  150.  * any difference between virtAddrPtr offset and segment offset.
  151.  * (This difference will only happen for shared segments.)
  152. */
  153. #define PageToOffSeg(page,virtAddrPtr) (PageToSeg((page)- \
  154.     segOffset(virtAddrPtr)+(virtAddrPtr->segPtr->offset)))
  155.  
  156. /*
  157.  * Macro to set all page map entries for the given virtual address.
  158.  */
  159. #define    SET_ALL_PAGE_MAP(virtAddr, pte) { \
  160.     int    __i; \
  161.     for (__i = 0; __i < VMMACH_CLUSTER_SIZE; __i++) { \
  162.     VmMachSetPageMap((Address)((virtAddr) + __i * VMMACH_PAGE_SIZE_INT),\
  163.     (VmMachPTE)((pte) + __i)); \
  164.     } \
  165. }
  166.  
  167. /*
  168.  * PMEG table entry structure.
  169.  */
  170. typedef struct {
  171.     List_Links            links;        /* Links so that the pmeg */
  172.                         /* can be in a list */
  173.     struct      Vm_Segment      *segPtr;        /* Back pointer to segment that
  174.                                                    this cluster is in */
  175.     int                hardSegNum;    /* The hardware segment number
  176.                            for this pmeg. */
  177.     int                pageCount;    /* Count of resident pages in
  178.                          * this pmeg. */
  179.     int                lockCount;    /* The number of times that
  180.                          * this PMEG has been locked.*/
  181.     int                flags;        /* Flags defined below. */
  182.  
  183. } PMEG;
  184.  
  185. /*
  186.  * Flags to indicate the state of a pmeg.
  187.  *
  188.  *    PMEG_DONT_ALLOC    This pmeg should not be reallocated.  This is 
  189.  *            when a pmeg cannot be reclaimed until it is
  190.  *            voluntarily freed.
  191.  *    PMEG_NEVER_FREE    Don't ever free this pmeg no matter what anybody says.
  192.  */
  193. #define    PMEG_DONT_ALLOC        0x1
  194. #define    PMEG_NEVER_FREE        0x2
  195.  
  196. /*
  197.  * Pmeg information.  pmegArray contains one entry for each pmeg.  pmegFreeList
  198.  * is a list of all pmegs that aren't being actively used.  pmegInuseList
  199.  * is a list of all pmegs that are being actively used.
  200.  */
  201. static    PMEG           pmegArray[VMMACH_NUM_PMEGS];
  202. static    List_Links       pmegFreeListHeader;
  203. static    List_Links       *pmegFreeList = &pmegFreeListHeader;
  204. static    List_Links       pmegInuseListHeader;
  205. static    List_Links       *pmegInuseList = &pmegInuseListHeader;
  206.  
  207. /*
  208.  * The context table structure.
  209.  */
  210. typedef struct VmMach_Context {
  211.     List_Links             links;      /* Links so that the contexts can be
  212.                          in a list. */
  213.     struct Proc_ControlBlock *procPtr;    /* A pointer to the process table entry
  214.                        for the process that is running in
  215.                        this context. */
  216.                     /* A reflection of the hardware context
  217.                      * map. */
  218.     unsigned char          map[VMMACH_NUM_SEGS_PER_CONTEXT];
  219.     int                 context;    /* Which context this is. */
  220.     int                 flags;    /* Defined below. */
  221. } VmMach_Context;
  222.  
  223. /*
  224.  * Context flags:
  225.  *
  226.  *         CONTEXT_IN_USE    This context is used by a process.
  227.  */
  228. #define    CONTEXT_IN_USE    0x1
  229.  
  230. /*
  231.  * Context information.  contextArray contains one entry for each context. 
  232.  * contextList is a list of contexts in LRU order.
  233.  */
  234. static    VmMach_Context    contextArray[VMMACH_NUM_CONTEXTS];
  235. static    List_Links       contextListHeader;
  236. static    List_Links       *contextList = &contextListHeader;
  237.  
  238. /*
  239.  * Map containing one entry for each virtual page.
  240.  */
  241. static    VmMachPTE        *refModMap;
  242.  
  243. /*
  244.  * Macros to translate from a virtual page to a physical page and back.
  245.  */
  246. #define    VirtToPhysPage(pfNum) ((pfNum) << VMMACH_CLUSTER_SHIFT)
  247. #define    PhysToVirtPage(pfNum) ((pfNum) >> VMMACH_CLUSTER_SHIFT)
  248.  
  249. /*
  250.  * Macro to get a pointer into a software segment's hardware segment table.
  251.  */
  252. #ifdef CLEAN
  253. #define GetHardSegPtr(machPtr, segNum) \
  254.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset)
  255. #else
  256. #define GetHardSegPtr(machPtr, segNum) \
  257.     ( ((unsigned)((segNum) - (machPtr)->offset) > (machPtr)->numSegs) ? \
  258.     (panic("Invalid segNum\n"),(machPtr)->segTablePtr) : \
  259.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset) )
  260. #endif
  261.  
  262. /*
  263.  * The maximum amount of kernel code + data available. 
  264.  */
  265. int    vmMachKernMemSize = VMMACH_MAX_KERN_SIZE;
  266.  
  267. /*
  268.  * Unix compatibility debug flag.
  269.  */
  270. extern int    debugVmStubs;
  271.  
  272. /*
  273.  * The segment that is used to map a segment into a process's virtual address
  274.  * space for cross-address-space copies.
  275.  */
  276. #define    MAP_SEG_NUM (VMMACH_MAP_SEG_ADDR >> VMMACH_SEG_SHIFT)
  277.  
  278. static void MMUInit _ARGS_((int firstFreeSegment));
  279. static int GetNumPages _ARGS_((void));
  280. static int PMEGGet _ARGS_((Vm_Segment *softSegPtr, int hardSegNum,
  281.     Boolean flags));
  282. static void PMEGFree _ARGS_((int pmegNum));
  283. static Boolean PMEGLock _ARGS_((register VmMach_SegData *machPtr,
  284.     int segNum));
  285. static void ByteFill _ARGS_((register unsigned int fillByte,
  286.     register int numBytes, Address destPtr));
  287. static void SetupContext _ARGS_((register Proc_ControlBlock *procPtr));
  288. static void PageInvalidate _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  289.     unsigned int virtPage, Boolean segDeletion));
  290. static void VmMach_Unalloc _ARGS_((VmMach_SharedData *sharedData,
  291.     Address addr));
  292.  
  293. static    VmMach_SegData    *sysMachPtr;
  294. Address            vmMachPTESegAddr;
  295. Address            vmMachPMEGSegAddr;
  296.  
  297.  
  298. /*
  299.  * ----------------------------------------------------------------------------
  300.  *
  301.  * VmMach_BootInit --
  302.  *
  303.  *      Do hardware dependent boot time initialization.
  304.  *
  305.  * Results:
  306.  *      None.
  307.  *
  308.  * Side effects:
  309.  *      Hardware page map for the kernel is initialized.  Also the various size
  310.  *     fields are filled in.
  311.  *
  312.  * ----------------------------------------------------------------------------
  313.  */
  314. void
  315. VmMach_BootInit(pageSizePtr, pageShiftPtr, pageTableIncPtr, kernMemSizePtr,
  316.         numKernPagesPtr, maxSegsPtr, maxProcessesPtr)
  317.     int    *pageSizePtr;
  318.     int    *pageShiftPtr;
  319.     int    *pageTableIncPtr;
  320.     int    *kernMemSizePtr;
  321.     int    *numKernPagesPtr;
  322.     int    *maxSegsPtr;
  323.     int *maxProcessesPtr;
  324. {
  325.     register Address    virtAddr;
  326.     register int    i;
  327.     int            kernPages;
  328.     int            numPages;
  329.  
  330. #ifdef multiprocessor
  331.     Sync_SemInitDynamic(&vmMachMutex, "Vm:vmMachMutex");
  332. #endif
  333.  
  334.     kernPages = VMMACH_BOOT_MAP_PAGES;
  335.     /*
  336.      * Map all of the kernel memory that we might need one for one.  We know
  337.      * that the monitor maps the first part of memory one for one but for some
  338.      * reason it doesn't map enough.  We assume that the pmegs have been
  339.      * mapped correctly.
  340.      */
  341.     for (i = 0, virtAddr = (Address)mach_KernStart; 
  342.      i < kernPages;
  343.      i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  344.         VmMachSetPageMap(virtAddr, 
  345.         (VmMachPTE)(VMMACH_KRW_PROT | VMMACH_RESIDENT_BIT | i));
  346.     }
  347.  
  348.     /*
  349.      * Do boot time allocation.
  350.      */
  351.     sysMachPtr = (VmMach_SegData *)Vm_BootAlloc(sizeof(VmMach_SegData) + 
  352.                         VMMACH_NUM_SEGS_PER_CONTEXT);
  353.     numPages = GetNumPages();
  354.     refModMap = (VmMachPTE *)Vm_BootAlloc(sizeof(VmMachPTE) * numPages);
  355.  
  356.     /*
  357.      * Return lots of sizes to the machine independent module who called us.
  358.      */
  359.     *pageSizePtr = VMMACH_PAGE_SIZE;
  360.     *pageShiftPtr = VMMACH_PAGE_SHIFT;
  361.     *pageTableIncPtr = VMMACH_PAGE_TABLE_INCREMENT;
  362.     /*
  363.      * Set max size for kernel code and data to vmMachKernMemSize or
  364.      * the amount of physical memory whichever is less.
  365.      */
  366.     if (vmMachKernMemSize > (numPages*VMMACH_PAGE_SIZE)) {
  367.     vmMachKernMemSize = numPages*VMMACH_PAGE_SIZE;
  368.     }
  369.     *kernMemSizePtr = vmMachKernMemSize;
  370.     *maxProcessesPtr = VMMACH_MAX_KERN_STACKS;
  371.     *numKernPagesPtr = GetNumPages();
  372.     /* 
  373.      * We don't care how many software segments there are so return -1 as
  374.      * the max.
  375.      */
  376.     *maxSegsPtr = -1;
  377. }
  378.  
  379.  
  380. /*
  381.  * ----------------------------------------------------------------------------
  382.  *
  383.  * GetNumPages --
  384.  *
  385.  *     Determine how many pages of physical memory there are.
  386.  *
  387.  * Results:
  388.  *     The number of physical pages.
  389.  *
  390.  * Side effects:
  391.  *     None.
  392.  *
  393.  * ----------------------------------------------------------------------------
  394.  */
  395. static int
  396. GetNumPages()
  397. {
  398. #ifdef sun3
  399.     return(*romVectorPtr->memoryAvail / VMMACH_PAGE_SIZE);
  400. #else
  401.     return(*romVectorPtr->memorySize / VMMACH_PAGE_SIZE);
  402. #endif
  403. }
  404.  
  405. /*
  406.  * ----------------------------------------------------------------------------
  407.  *
  408.  * VmMach_AllocKernSpace --
  409.  *
  410.  *     Allocate memory for machine dependent stuff in the kernels VAS.
  411.  *    This allocates space used to map PMEG and PTE registers
  412.  *    into kernel virtual space.  Two segments are reserved.
  413.  *
  414.  * Results:
  415.  *     The kernel virtual address after the reserved area.
  416.  *
  417.  * Side effects:
  418.  *     Sets vmMachPTESegAddr and vmMachPMEGSegAddr.
  419.  *
  420.  * ----------------------------------------------------------------------------
  421.  */
  422. Address
  423. VmMach_AllocKernSpace(baseAddr)
  424.     Address    baseAddr;
  425. {
  426.     baseAddr = (Address) (((unsigned int)baseAddr + VMMACH_SEG_SIZE - 1) / 
  427.                     VMMACH_SEG_SIZE * VMMACH_SEG_SIZE);
  428.     vmMachPTESegAddr = baseAddr;
  429.     vmMachPMEGSegAddr = baseAddr + VMMACH_SEG_SIZE;
  430.     return(baseAddr + 2 * VMMACH_SEG_SIZE);
  431. }
  432.  
  433.  
  434. /*
  435.  * ----------------------------------------------------------------------------
  436.  *
  437.  * VmMach_Init --
  438.  *
  439.  *     Initialize all virtual memory data structures.
  440.  *
  441.  * Results:
  442.  *     None.
  443.  *
  444.  * Side effects:
  445.  *     All virtual memory linked lists and arrays are initialized.
  446.  *
  447.  * ----------------------------------------------------------------------------
  448.  */
  449. void
  450. VmMach_Init(firstFreePage)
  451.     int    firstFreePage;    /* Virtual page that is the first free for the 
  452.              * kernel. */
  453. {
  454.     register     unsigned char    *segTablePtr;
  455.     register     VmMachPTE    pte;
  456.     register    int         i;
  457.     int             firstFreeSegment;
  458.     Address            virtAddr;
  459.     Address            lastCodeAddr;
  460.     extern    int        etext;
  461.  
  462.     /*
  463.      * Initialize the kernel's hardware segment table.
  464.      */
  465.     vm_SysSegPtr->machPtr = sysMachPtr;
  466.     sysMachPtr->numSegs = VMMACH_NUM_SEGS_PER_CONTEXT;
  467.     sysMachPtr->offset = PageToSeg(vm_SysSegPtr->offset);
  468.     sysMachPtr->segTablePtr =
  469.         (unsigned char *) ((Address)sysMachPtr + sizeof(VmMach_SegData));
  470.     ByteFill(VMMACH_INV_PMEG, VMMACH_NUM_SEGS_PER_CONTEXT,
  471.           (Address)sysMachPtr->segTablePtr);
  472.  
  473.     /*
  474.      * Determine which hardware segment is the first that is not in use.
  475.      */
  476.     firstFreeSegment = ((firstFreePage - 1) << VMMACH_PAGE_SHIFT) / 
  477.                     VMMACH_SEG_SIZE + 1;
  478.     firstFreeSegment += (unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT;
  479.  
  480.     /* 
  481.      * Initialize the PMEG and context tables and lists.
  482.      */
  483.     MMUInit(firstFreeSegment);
  484.  
  485.     /*
  486.      * Initialize the page map.
  487.      */
  488.     bzero((Address)refModMap, sizeof(VmMachPTE) * GetNumPages());
  489.  
  490.     /*
  491.      * The code segment is read only and all other in use kernel memory
  492.      * is read/write.  Since the loader may put the data in the same page
  493.      * as the last code page, the last code page is also read/write.
  494.      */
  495.     lastCodeAddr = (Address) ((unsigned)&etext - VMMACH_PAGE_SIZE);
  496.     for (i = 0, virtAddr = (Address)mach_KernStart;
  497.      i < firstFreePage;
  498.      virtAddr += VMMACH_PAGE_SIZE, i++) {
  499.     if (virtAddr >= (Address)MACH_CODE_START && 
  500.         virtAddr <= lastCodeAddr) {
  501.         pte = VMMACH_RESIDENT_BIT | VMMACH_KR_PROT | 
  502.               i * VMMACH_CLUSTER_SIZE;
  503.     } else {
  504.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  505.               i * VMMACH_CLUSTER_SIZE;
  506.         }
  507.     SET_ALL_PAGE_MAP(virtAddr, pte);
  508.     }
  509.  
  510.     /*
  511.      * Protect the bottom of the kernel stack.
  512.      */
  513.     SET_ALL_PAGE_MAP((Address)mach_StackBottom, (VmMachPTE)0);
  514.  
  515.     /*
  516.      * Invalid until the end of the last segment
  517.      */
  518.     for (;virtAddr < (Address) (firstFreeSegment << VMMACH_SEG_SHIFT);
  519.      virtAddr += VMMACH_PAGE_SIZE) {
  520.     SET_ALL_PAGE_MAP(virtAddr, (VmMachPTE)0);
  521.     }
  522.  
  523.     /* 
  524.      * Zero out the invalid pmeg.
  525.      */
  526.     VmMachPMEGZero(VMMACH_INV_PMEG);
  527.  
  528.     /*
  529.      * Finally copy the kernels context to each of the other contexts.
  530.      */
  531.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  532.     if (i == VMMACH_KERN_CONTEXT) {
  533.         continue;
  534.     }
  535.     VmMachSetUserContext(i);
  536.     for (virtAddr = (Address)mach_KernStart,
  537.          segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  538.          virtAddr < (Address)(VMMACH_NUM_SEGS_PER_CONTEXT*VMMACH_SEG_SIZE);
  539.          virtAddr += VMMACH_SEG_SIZE, segTablePtr++) {
  540.         VmMachSetSegMap(virtAddr, *segTablePtr);
  541.     }
  542.     }
  543.     VmMachSetUserContext(VMMACH_KERN_CONTEXT);
  544.     if (Mach_GetMachineType() == SYS_SUN_3_50) {
  545.     unsigned int vidPage;
  546.  
  547. #define    VIDEO_START    0x100000
  548. #define    VIDEO_SIZE    0x20000
  549.     vidPage = VIDEO_START / VMMACH_PAGE_SIZE;
  550.     if (firstFreePage > vidPage) {
  551.         panic("VmMach_Init: We overran video memory.\n");
  552.     }
  553.     /*
  554.      * On 3/50's the display is kept in main memory beginning at 1 
  555.      * Mbyte and going for 128 kbytes.  Reserve this memory so VM
  556.      * doesn't try to use it.
  557.      */
  558.     for (;vidPage < (VIDEO_START + VIDEO_SIZE) / VMMACH_PAGE_SIZE;
  559.          vidPage++) {
  560.         Vm_ReservePage(vidPage);
  561.     }
  562.     }
  563. }
  564.  
  565.  
  566. /*
  567.  *----------------------------------------------------------------------
  568.  *
  569.  * MMUInit --
  570.  *
  571.  *    Initialize the context table and lists and the Pmeg table and 
  572.  *    lists.
  573.  *
  574.  * Results:
  575.  *    None.
  576.  *
  577.  * Side effects:
  578.  *    Context table and Pmeg table are initialized.  Also context list
  579.  *    and pmeg list are initialized.
  580.  *
  581.  *----------------------------------------------------------------------
  582.  */
  583. static void
  584. MMUInit(firstFreeSegment)
  585.     int        firstFreeSegment;
  586. {
  587.     register    int        i;
  588.     register    PMEG        *pmegPtr;
  589.     register    unsigned char    *segTablePtr;
  590.     int                pageCluster;
  591. #ifdef sun3
  592.     int                dontUse;
  593. #endif
  594.  
  595.     /*
  596.      * Initialize the context table.
  597.      */
  598.     contextArray[VMMACH_KERN_CONTEXT].flags = CONTEXT_IN_USE;
  599.     List_Init(contextList);
  600.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  601.     if (i != VMMACH_KERN_CONTEXT) {
  602.         contextArray[i].flags = 0;
  603.         List_Insert((List_Links *) &contextArray[i], 
  604.             LIST_ATREAR(contextList));
  605.     }
  606.     contextArray[i].context = i;
  607.     }
  608.  
  609.     /*
  610.      * Initialize the page cluster list.
  611.      */
  612.     List_Init(pmegFreeList);
  613.     List_Init(pmegInuseList);
  614.  
  615.     /*
  616.      * Initialize the pmeg structure.
  617.      */
  618.     bzero((Address)pmegArray, VMMACH_NUM_PMEGS * sizeof(PMEG));
  619.     for (i = 0, pmegPtr = pmegArray; 
  620.      i < VMMACH_NUM_PMEGS; 
  621.      i++, pmegPtr++) {
  622.     pmegPtr->segPtr = (Vm_Segment *) NIL;
  623.     pmegPtr->flags = PMEG_DONT_ALLOC;
  624.     }
  625.  
  626. #ifdef sun3
  627.     i = 0;
  628. #else
  629.     /*
  630.      * Segment 0 is left alone because it is required for the monitor.
  631.      */
  632.     pmegArray[0].segPtr = (Vm_Segment *)NIL;
  633.     pmegArray[0].hardSegNum = 0;
  634.     i = 1;
  635. #endif
  636.  
  637.     /*
  638.      * Invalidate all hardware segments from segment 1 up to the beginning
  639.      * of the kernel.
  640.      */
  641.     for (; i < ((unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT); i++) {
  642.     VmMachSetSegMap((Address)(i << VMMACH_SEG_SHIFT), VMMACH_INV_PMEG);
  643.     }
  644.  
  645.     /*
  646.      * Reserve all pmegs that have kernel code or heap.
  647.      */
  648.     for (segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  649.          i < firstFreeSegment;
  650.      i++, segTablePtr++) {
  651.     pageCluster = VmMachGetSegMap((Address) (i << VMMACH_SEG_SHIFT));
  652.     pmegArray[pageCluster].pageCount = VMMACH_NUM_PAGES_PER_SEG;
  653.     pmegArray[pageCluster].segPtr = vm_SysSegPtr;
  654.     pmegArray[pageCluster].hardSegNum = i;
  655.     *segTablePtr = pageCluster;
  656.     }
  657.  
  658.     /*
  659.      * Invalidate all hardware segments that aren't in code or heap and are 
  660.      * before the specially mapped page clusters.
  661.      */
  662.     for (; i < VMMACH_FIRST_SPECIAL_SEG; i++, segTablePtr++) {
  663.     VmMachSetSegMap((Address)(i << VMMACH_SEG_SHIFT), VMMACH_INV_PMEG);
  664.     }
  665.  
  666.     /*
  667.      * Mark the invalid pmeg so that it never gets used.
  668.      */
  669.     pmegArray[VMMACH_INV_PMEG].segPtr = vm_SysSegPtr;
  670.     pmegArray[VMMACH_INV_PMEG].flags = PMEG_NEVER_FREE;
  671.  
  672.     /*
  673.      * Now reserve the rest of the page clusters that have been set up by
  674.      * the monitor.  Don't reserve any PMEGs that don't have any valid 
  675.      * mappings in them.
  676.      */
  677.     for (; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++, segTablePtr++) {
  678.     Address        virtAddr;
  679.     int        j;
  680.     VmMachPTE    pte;
  681.     Boolean        inusePMEG;
  682.  
  683.     virtAddr = (Address) (i << VMMACH_SEG_SHIFT);
  684.     pageCluster = VmMachGetSegMap(virtAddr);
  685.     if (pageCluster != VMMACH_INV_PMEG) {
  686.         inusePMEG = FALSE;
  687.         for (j = 0; 
  688.              j < VMMACH_NUM_PAGES_PER_SEG_INT; 
  689.          j++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  690.         pte = VmMachGetPageMap(virtAddr);
  691.         /* printf("%x: %x\n", virtAddr, pte); */
  692.         if ((pte & VMMACH_RESIDENT_BIT) &&
  693.             (pte & (VMMACH_TYPE_FIELD|VMMACH_PAGE_FRAME_FIELD)) != 0) {
  694.             /*
  695.              * A PMEG contains a valid mapping if the resident
  696.              * bit is set and the page frame and type field
  697.              * are non-zero.  On Sun 2/50's the PROM sets
  698.              * the resident bit but leaves the page frame equal
  699.              * to zero.
  700.              */
  701.             if (!inusePMEG) {
  702.             pmegArray[pageCluster].segPtr = vm_SysSegPtr;
  703.             pmegArray[pageCluster].hardSegNum = i;
  704.             pmegArray[pageCluster].flags = PMEG_NEVER_FREE;
  705.             inusePMEG = TRUE;
  706.             }
  707.         } else {
  708.             VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  709.         }
  710.         }
  711.         virtAddr -= VMMACH_SEG_SIZE;
  712.         if (!inusePMEG ||
  713.             (virtAddr >= (Address)VMMACH_DMA_START_ADDR &&
  714.          virtAddr < (Address)(VMMACH_DMA_START_ADDR+VMMACH_DMA_SIZE))) {
  715. #ifdef PRINT_ZAP
  716.         int z;
  717.         /* 
  718.          * We didn't find any valid mappings in the PMEG or the PMEG
  719.          * is in DMA space so delete it.
  720.          */
  721.         printf("Zapping segment at virtAddr %x\n", virtAddr);
  722.         for (z = 0; z < 100000; z++) {
  723.         }
  724. #endif
  725.  
  726.         VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  727.         pageCluster = VMMACH_INV_PMEG;
  728.         }
  729.     }
  730.     *segTablePtr = pageCluster;
  731.     }
  732.  
  733. #ifdef sun3
  734.     /*
  735.      * We can't use the hardware segment that corresponds to the
  736.      * last segment of physical memory for some reason.  Zero it out
  737.      * and can't reboot w/o powering the machine off.
  738.      */
  739.     dontUse = (*romVectorPtr->memoryAvail - 1) / VMMACH_SEG_SIZE;
  740. #endif
  741.  
  742.     /*
  743.      * Now finally, all page clusters that have a NIL segment pointer are
  744.      * put onto the page cluster fifo.  On a Sun-3 one hardware segment is 
  745.      * off limits for some reason.  Zero it out and can't reboot w/o 
  746.      * powering the machine off.
  747.      */
  748.     for (i = 0, pmegPtr = pmegArray; 
  749.      i < VMMACH_NUM_PMEGS;
  750.      i++, pmegPtr++) {
  751.     if (pmegPtr->segPtr == (Vm_Segment *) NIL 
  752. #ifdef sun3
  753.         && i != dontUse
  754. #endif
  755.     ) {
  756.         List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegFreeList));
  757.         pmegPtr->flags = 0;
  758.         VmMachPMEGZero(i);
  759.     }
  760.     }
  761. }
  762.  
  763.  
  764. /*
  765.  * ----------------------------------------------------------------------------
  766.  *
  767.  * VmMach_SegInit --
  768.  *
  769.  *      Initialize hardware dependent data for a segment.
  770.  *
  771.  * Results:
  772.  *      None.
  773.  *
  774.  * Side effects:
  775.  *      Machine dependent data struct and is allocated and initialized.
  776.  *
  777.  * ----------------------------------------------------------------------------
  778.  */
  779. void
  780. VmMach_SegInit(segPtr)
  781.     Vm_Segment    *segPtr;
  782. {
  783.     register    VmMach_SegData    *segDataPtr;
  784.     int                segTableSize;
  785.  
  786.     if (segPtr->type == VM_CODE) {
  787.     segTableSize =
  788.         (segPtr->ptSize + segPtr->offset + VMMACH_NUM_PAGES_PER_SEG - 1) / 
  789.                             VMMACH_NUM_PAGES_PER_SEG;
  790.     } else {
  791.     segTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  792.     }
  793.     segDataPtr = 
  794.     (VmMach_SegData *)malloc(sizeof(VmMach_SegData) + segTableSize);
  795.     segDataPtr->numSegs = segTableSize;
  796.     segDataPtr->offset = PageToSeg(segPtr->offset);
  797.     segDataPtr->segTablePtr =
  798.         (unsigned char *) ((Address)segDataPtr + sizeof(VmMach_SegData));
  799.     ByteFill(VMMACH_INV_PMEG, segTableSize, (Address)segDataPtr->segTablePtr);
  800.     segPtr->machPtr = segDataPtr;
  801.     /*
  802.      * Set the minimum and maximum virtual addresses for this segment to
  803.      * be as small and as big as possible respectively because things will
  804.      * be prevented from growing automatically as soon as segments run into
  805.      * each other.
  806.      */
  807.     segPtr->minAddr = (Address)0;
  808.     segPtr->maxAddr = (Address)0x7fffffff;
  809. }
  810.  
  811. static void    CopySegData();
  812.  
  813.  
  814. /*
  815.  *----------------------------------------------------------------------
  816.  *
  817.  * VmMach_SegExpand --
  818.  *
  819.  *    Allocate more space for the machine dependent structure.
  820.  *
  821.  * Results:
  822.  *    None.
  823.  *
  824.  * Side effects:
  825.  *    Memory allocated for a new hardware segment table.
  826.  *
  827.  *----------------------------------------------------------------------
  828.  */
  829. /*ARGSUSED*/
  830. void
  831. VmMach_SegExpand(segPtr, firstPage, lastPage)
  832.     register    Vm_Segment    *segPtr;    /* Segment to expand. */
  833.     int                firstPage;    /* First page to add. */
  834.     int                lastPage;    /* Last page to add. */
  835. {
  836.     int                newSegTableSize;
  837.     register    VmMach_SegData    *oldSegDataPtr;
  838.     register    VmMach_SegData    *newSegDataPtr;
  839.  
  840.     newSegTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  841.     oldSegDataPtr = segPtr->machPtr;
  842.     if (newSegTableSize <= oldSegDataPtr->numSegs) {
  843.     return;
  844.     }
  845.     newSegDataPtr = 
  846.     (VmMach_SegData *)malloc(sizeof(VmMach_SegData) + newSegTableSize);
  847.     newSegDataPtr->numSegs = newSegTableSize;
  848.     newSegDataPtr->offset = PageToSeg(segPtr->offset);
  849.     newSegDataPtr->segTablePtr =
  850.         (unsigned char *) ((Address)newSegDataPtr + sizeof(VmMach_SegData));
  851.     CopySegData(segPtr, oldSegDataPtr, newSegDataPtr);
  852.     free((Address)oldSegDataPtr);
  853. }
  854.  
  855.  
  856. /*
  857.  *----------------------------------------------------------------------
  858.  *
  859.  * CopySegData --
  860.  *
  861.  *    Copy over the old hardware segment data into the new expanded
  862.  *    structure.
  863.  *
  864.  * Results:
  865.  *    None.
  866.  *
  867.  * Side effects:
  868.  *    The hardware segment table is copied.
  869.  *
  870.  *----------------------------------------------------------------------
  871.  */
  872. static void
  873. CopySegData(segPtr, oldSegDataPtr, newSegDataPtr)
  874.     register    Vm_Segment    *segPtr;    /* The segment to add the
  875.                            virtual pages to. */
  876.     register    VmMach_SegData    *oldSegDataPtr;
  877.     register    VmMach_SegData    *newSegDataPtr;
  878. {
  879.     MASTER_LOCK(vmMachMutexPtr);
  880.  
  881.     if (segPtr->type == VM_HEAP) {
  882.     /*
  883.      * Copy over the hardware segment table into the lower part
  884.      * and set the rest to invalid.
  885.      */
  886.     bcopy((Address)oldSegDataPtr->segTablePtr,
  887.         (Address)newSegDataPtr->segTablePtr, oldSegDataPtr->numSegs);
  888.     ByteFill(VMMACH_INV_PMEG,
  889.       newSegDataPtr->numSegs - oldSegDataPtr->numSegs,
  890.       (Address)(newSegDataPtr->segTablePtr + oldSegDataPtr->numSegs));
  891.     } else {
  892.     /*
  893.      * Copy the current segment table into the high part of the
  894.      * new segment table and set the lower part to invalid.
  895.      */
  896.     bcopy((Address)oldSegDataPtr->segTablePtr,
  897.         (Address)(newSegDataPtr->segTablePtr + 
  898.         newSegDataPtr->numSegs - oldSegDataPtr->numSegs),
  899.         oldSegDataPtr->numSegs);
  900.     ByteFill(VMMACH_INV_PMEG, 
  901.         newSegDataPtr->numSegs - oldSegDataPtr->numSegs,
  902.         (Address)newSegDataPtr->segTablePtr);
  903.     }
  904.     segPtr->machPtr = newSegDataPtr;
  905.  
  906.     MASTER_UNLOCK(vmMachMutexPtr);
  907. }
  908.  
  909. static void    SegDelete();
  910.  
  911. /*
  912.  * ----------------------------------------------------------------------------
  913.  *
  914.  * VmMach_SegDelete --
  915.  *
  916.  *      Free hardware dependent resources for this software segment.
  917.  *
  918.  * Results:
  919.  *      None.
  920.  *
  921.  * Side effects:
  922.  *      Machine dependent struct freed and the pointer in the segment
  923.  *    is set to NIL.
  924.  *
  925.  * ----------------------------------------------------------------------------
  926.  */
  927. void
  928. VmMach_SegDelete(segPtr)
  929.     register    Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  930. {
  931.  
  932.     SegDelete(segPtr);
  933.     free((Address)segPtr->machPtr);
  934.     segPtr->machPtr = (VmMach_SegData *)NIL;
  935. }
  936.  
  937.  
  938. /*
  939.  * ----------------------------------------------------------------------------
  940.  *
  941.  * SegDelete --
  942.  *
  943.  *      Free up any pmegs used by this segment.
  944.  *
  945.  * Results:
  946.  *      None.
  947.  *
  948.  * Side effects:
  949.  *      All pmegs used by this segment are freed.
  950.  *
  951.  * ----------------------------------------------------------------------------
  952.  */
  953. static void
  954. SegDelete(segPtr)
  955.     Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  956. {
  957.     register    int         i;
  958.     register    unsigned char     *pmegPtr;
  959.     register    VmMach_SegData    *machPtr;
  960.  
  961.     MASTER_LOCK(vmMachMutexPtr);
  962.  
  963.     machPtr = segPtr->machPtr;
  964.     for (i = 0, pmegPtr = machPtr->segTablePtr;
  965.          i < machPtr->numSegs;
  966.      i++, pmegPtr++) {
  967.     if (*pmegPtr != VMMACH_INV_PMEG) {
  968.         PMEGFree((int) *pmegPtr);
  969.     }
  970.     }
  971.  
  972.     MASTER_UNLOCK(vmMachMutexPtr);
  973. }
  974.  
  975.  
  976. /*
  977.  *----------------------------------------------------------------------
  978.  *
  979.  * VmMach_ProcInit --
  980.  *
  981.  *    Initalize the machine dependent part of the VM proc info.
  982.  *
  983.  * Results:
  984.  *    None.
  985.  *
  986.  * Side effects:
  987.  *    Machine dependent proc info is initialized.
  988.  *
  989.  *----------------------------------------------------------------------
  990.  */
  991. void
  992. VmMach_ProcInit(vmPtr)
  993.     register    Vm_ProcInfo    *vmPtr;
  994. {
  995.     if (vmPtr->machPtr == (VmMach_ProcData *)NIL) {
  996.     vmPtr->machPtr = (VmMach_ProcData *)malloc(sizeof(VmMach_ProcData));
  997.     }
  998.     vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  999.     vmPtr->machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1000.     vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  1001. }
  1002.  
  1003.  
  1004. /*
  1005.  * ----------------------------------------------------------------------------
  1006.  *
  1007.  * PMEGGet --
  1008.  *
  1009.  *      Return the next pmeg from the list of available pmegs.  If the 
  1010.  *      lock flag is set then the pmeg is removed from the pmeg list.
  1011.  *      Otherwise it is moved to the back.
  1012.  *
  1013.  * Results:
  1014.  *      The pmeg number that is allocated.
  1015.  *
  1016.  * Side effects:
  1017.  *      A pmeg is either removed from the pmeg list or moved to the back.
  1018.  *
  1019.  * ----------------------------------------------------------------------------
  1020.  */
  1021. static int
  1022. PMEGGet(softSegPtr, hardSegNum, flags)
  1023.     Vm_Segment     *softSegPtr;    /* Which software segment this is. */
  1024.     int        hardSegNum;    /* Which hardware segment in the software 
  1025.                    segment that this is */
  1026.     Boolean    flags;        /* Flags that indicate the state of the pmeg. */
  1027. {
  1028.     register PMEG        *pmegPtr;
  1029.     register Vm_Segment        *segPtr;
  1030.     register VmMachPTE        *ptePtr;
  1031.     register VmMach_Context    *contextPtr;
  1032.     register int        i;
  1033.     register VmMachPTE        hardPTE;
  1034.     VmMachPTE            pteArray[VMMACH_NUM_PAGES_PER_SEG_INT];
  1035.     int                     oldContext;
  1036.     int                pmegNum;
  1037.     Address            virtAddr;
  1038.     Boolean            found = FALSE;
  1039.  
  1040.     if (List_IsEmpty(pmegFreeList)) {
  1041.     LIST_FORALL(pmegInuseList, (List_Links *)pmegPtr) {
  1042.         if (pmegPtr->lockCount == 0) {
  1043.         found = TRUE;
  1044.         break;
  1045.         }
  1046.     }
  1047.     if (!found) {
  1048.         panic("Pmeg lists empty\n");
  1049.         return(VMMACH_INV_PMEG);
  1050.     }
  1051.     } else {
  1052.     pmegPtr = (PMEG *)List_First(pmegFreeList);
  1053.     }
  1054.     pmegNum = pmegPtr - pmegArray;
  1055.  
  1056.     if (pmegPtr->segPtr != (Vm_Segment *) NIL) {
  1057.     /*
  1058.      * Need to steal the pmeg from its current owner.
  1059.      */
  1060.     vmStat.machDepStat.stealPmeg++;
  1061.     segPtr = pmegPtr->segPtr;
  1062.     *GetHardSegPtr(segPtr->machPtr, pmegPtr->hardSegNum) = VMMACH_INV_PMEG;
  1063.     virtAddr = (Address) (pmegPtr->hardSegNum << VMMACH_SEG_SHIFT);
  1064.     /*
  1065.      * Delete the pmeg from all appropriate contexts.
  1066.      */
  1067.     oldContext = VmMachGetContextReg();
  1068.         if (segPtr->type == VM_SYSTEM) {
  1069.         for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1070.         VmMachSetContextReg(i);
  1071.         VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1072.         }
  1073.         } else {
  1074.         for (i = 1, contextPtr = &contextArray[1];
  1075.          i < VMMACH_NUM_CONTEXTS; 
  1076.          i++, contextPtr++) {
  1077.         if (contextPtr->flags & CONTEXT_IN_USE) {
  1078.             if (contextPtr->map[pmegPtr->hardSegNum] == pmegNum) {
  1079.             VmMachSetContextReg(i);
  1080.             contextPtr->map[pmegPtr->hardSegNum] = VMMACH_INV_PMEG;
  1081.             VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1082.             }
  1083.             if (contextPtr->map[MAP_SEG_NUM] == pmegNum) {
  1084.             VmMachSetContextReg(i);
  1085.             contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1086.             VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR,
  1087.                     VMMACH_INV_PMEG);
  1088.             }
  1089.         }
  1090.         }
  1091.         }
  1092.     VmMachSetContextReg(oldContext);
  1093.     /*
  1094.      * Read out all reference and modify bits from the pmeg.
  1095.      */
  1096.     if (pmegPtr->pageCount > 0) {
  1097.         Boolean    printedStealPMEG = FALSE;
  1098.  
  1099.         ptePtr = pteArray;
  1100.         VmMachReadAndZeroPMEG(pmegNum, ptePtr);
  1101.         for (i = 0;
  1102.          i < VMMACH_NUM_PAGES_PER_SEG_INT;
  1103.          i++, ptePtr++) {
  1104.         hardPTE = *ptePtr;
  1105.         if ((hardPTE & VMMACH_RESIDENT_BIT) &&
  1106.             (hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT))) {
  1107.             refModMap[PhysToVirtPage(hardPTE & VMMACH_PAGE_FRAME_FIELD)]
  1108.              |= hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  1109.         }
  1110.         }
  1111.      }
  1112.     }
  1113.  
  1114.     /* Initialize the pmeg and delete it from the fifo.  If we aren't 
  1115.      * supposed to lock this pmeg, then put it at the rear of the list.
  1116.      */
  1117.     pmegPtr->segPtr = softSegPtr;
  1118.     pmegPtr->hardSegNum = hardSegNum;
  1119.     pmegPtr->pageCount = 0;
  1120.     List_Remove((List_Links *) pmegPtr);
  1121.     if (!(flags & PMEG_DONT_ALLOC)) {
  1122.     List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegInuseList));
  1123.     }
  1124.     pmegPtr->flags = flags;
  1125.  
  1126.     return(pmegNum);
  1127. }
  1128.  
  1129.  
  1130. /*
  1131.  * ----------------------------------------------------------------------------
  1132.  *
  1133.  * PMEGFree --
  1134.  *
  1135.  *      Return the given pmeg to the pmeg list.
  1136.  *
  1137.  * Results:
  1138.  *      None.
  1139.  *
  1140.  * Side effects:
  1141.  *      The pmeg is returned to the pmeg list.
  1142.  *
  1143.  * ----------------------------------------------------------------------------
  1144.  */
  1145. static void
  1146. PMEGFree(pmegNum)
  1147.     int     pmegNum;    /* Which pmeg to free */
  1148. {
  1149.     register    PMEG    *pmegPtr;
  1150.  
  1151.     pmegPtr = &pmegArray[pmegNum];
  1152.     /*
  1153.      * If this pmeg can never be freed then don't free it.  This case can
  1154.      * occur when a device is mapped into a user's address space.
  1155.      */
  1156.     if (pmegPtr->flags & PMEG_NEVER_FREE) {
  1157.     return;
  1158.     }
  1159.     if (pmegPtr->pageCount > 0) {
  1160.     VmMachPMEGZero(pmegNum);
  1161.     }
  1162.     pmegPtr->segPtr = (Vm_Segment *) NIL;
  1163.     if (pmegPtr->pageCount == 0 || !(pmegPtr->flags & PMEG_DONT_ALLOC)) {
  1164.     List_Remove((List_Links *) pmegPtr);
  1165.     }
  1166.     pmegPtr->flags = 0;
  1167.     pmegPtr->lockCount = 0;
  1168.     /*
  1169.      * Put this pmeg at the front of the pmeg free list.
  1170.      */
  1171.     List_Insert((List_Links *) pmegPtr, LIST_ATFRONT(pmegFreeList));
  1172. }
  1173.  
  1174.  
  1175. /*
  1176.  * ----------------------------------------------------------------------------
  1177.  *
  1178.  * PMEGLock --
  1179.  *
  1180.  *      Increment the lock count on a pmeg.
  1181.  *
  1182.  * Results:
  1183.  *      TRUE if there was a valid PMEG behind the given hardware segment.
  1184.  *
  1185.  * Side effects:
  1186.  *      The lock count is incremented if there is a valid pmeg at the given
  1187.  *    hardware segment.
  1188.  *
  1189.  * ----------------------------------------------------------------------------
  1190.  */
  1191. static Boolean
  1192. PMEGLock(machPtr, segNum)
  1193.     register VmMach_SegData    *machPtr;
  1194.     int                segNum;
  1195. {
  1196.     int pmegNum;
  1197.  
  1198.     MASTER_LOCK(vmMachMutexPtr);
  1199.  
  1200.     pmegNum = *GetHardSegPtr(machPtr, segNum);
  1201.     if (pmegNum != VMMACH_INV_PMEG) {
  1202.     pmegArray[pmegNum].lockCount++;
  1203.     MASTER_UNLOCK(vmMachMutexPtr);
  1204.     return(TRUE);
  1205.     } else {
  1206.     MASTER_UNLOCK(vmMachMutexPtr);
  1207.     return(FALSE);
  1208.     }
  1209. }
  1210.  
  1211.  
  1212. /*
  1213.  * ----------------------------------------------------------------------------
  1214.  *
  1215.  * VmMach_SetupContext --
  1216.  *
  1217.  *      Return the value of the context register for the given process.
  1218.  *    It is assumed that this routine is called on a uni-processor right
  1219.  *    before the process starts executing.
  1220.  *    
  1221.  * Results:
  1222.  *      None.
  1223.  *
  1224.  * Side effects:
  1225.  *      The context list is modified.
  1226.  *
  1227.  * ----------------------------------------------------------------------------
  1228.  */
  1229. ClientData
  1230. VmMach_SetupContext(procPtr)
  1231.     register    Proc_ControlBlock    *procPtr;
  1232. {
  1233.     register    VmMach_Context    *contextPtr;
  1234.  
  1235.     MASTER_LOCK(vmMachMutexPtr);
  1236.  
  1237.     while (TRUE) {
  1238.     contextPtr = procPtr->vmPtr->machPtr->contextPtr;
  1239.     if (contextPtr != (VmMach_Context *)NIL) {
  1240.         if (contextPtr != &contextArray[VMMACH_KERN_CONTEXT]) {
  1241.         List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  1242.         }
  1243.         MASTER_UNLOCK(vmMachMutexPtr);
  1244.         return((ClientData)contextPtr->context);
  1245.     }
  1246.         SetupContext(procPtr);
  1247.     }
  1248. }
  1249.  
  1250.  
  1251. /*
  1252.  * ----------------------------------------------------------------------------
  1253.  *
  1254.  * SetupContext --
  1255.  *
  1256.  *      Initialize the context for the given process.  If the process does
  1257.  *    not have a context associated with it then one is allocated.
  1258.  *
  1259.  *    Note that this routine runs unsynchronized even though it is using
  1260.  *    internal structures.  See the note above while this is OK.  I
  1261.  *     eliminated the monitor lock because it is unnecessary anyway and
  1262.  *    it slows down context-switching.
  1263.  *    
  1264.  * Results:
  1265.  *      None.
  1266.  *
  1267.  * Side effects:
  1268.  *      The context field in the process table entry and the context list are
  1269.  *     both modified if a new context is allocated.
  1270.  *
  1271.  * ----------------------------------------------------------------------------
  1272.  */
  1273. static void
  1274. SetupContext(procPtr)
  1275.     register    Proc_ControlBlock    *procPtr;
  1276. {
  1277.     register    VmMach_Context    *contextPtr;
  1278.     register    VmMach_SegData    *segDataPtr;
  1279.     register    Vm_ProcInfo    *vmPtr;
  1280.  
  1281.     vmPtr = procPtr->vmPtr;
  1282.     contextPtr = vmPtr->machPtr->contextPtr;
  1283.  
  1284.     if (procPtr->genFlags & (PROC_KERNEL | PROC_NO_VM)) {
  1285.     /*
  1286.      * This is a kernel process or a process that is exiting.
  1287.      * Set the context to kernel and return.
  1288.      */
  1289.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  1290.     vmPtr->machPtr->contextPtr = &contextArray[VMMACH_KERN_CONTEXT];
  1291.     return;
  1292.     }
  1293.  
  1294.     if (contextPtr == (VmMach_Context *)NIL) {
  1295.     /*
  1296.      * In this case there is no context setup for this process.  Therefore
  1297.      * we have to find a context, initialize the context table entry and 
  1298.      * initialize the context stuff in the proc table.
  1299.      */
  1300.     if (List_IsEmpty((List_Links *) contextList)) {
  1301.         panic("SetupContext: Context list empty\n");
  1302.     }
  1303.     /* 
  1304.      * Take the first context off of the context list.
  1305.      */
  1306.     contextPtr = (VmMach_Context *) List_First(contextList);
  1307.     if (contextPtr->flags & CONTEXT_IN_USE) {
  1308.         contextPtr->procPtr->vmPtr->machPtr->contextPtr =
  1309.                             (VmMach_Context *)NIL;
  1310.         vmStat.machDepStat.stealContext++;
  1311.     }
  1312.     /*
  1313.      * Initialize the context table entry.
  1314.      */
  1315.     contextPtr->flags = CONTEXT_IN_USE;
  1316.     contextPtr->procPtr = procPtr;
  1317.     vmPtr->machPtr->contextPtr = contextPtr;
  1318.     VmMachSetContextReg(contextPtr->context);
  1319.     /*
  1320.      * Set the context map.
  1321.      */
  1322.     ByteFill(VMMACH_INV_PMEG,
  1323.           (int)((unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT),
  1324.           (Address)contextPtr->map);
  1325.     segDataPtr = vmPtr->segPtrArray[VM_CODE]->machPtr;
  1326.     bcopy((Address)segDataPtr->segTablePtr, 
  1327.         (Address) (contextPtr->map + segDataPtr->offset),
  1328.         segDataPtr->numSegs);
  1329.     segDataPtr = vmPtr->segPtrArray[VM_HEAP]->machPtr;
  1330.     bcopy((Address)segDataPtr->segTablePtr, 
  1331.         (Address) (contextPtr->map + segDataPtr->offset),
  1332.         segDataPtr->numSegs);
  1333.     segDataPtr = vmPtr->segPtrArray[VM_STACK]->machPtr;
  1334.     bcopy((Address)segDataPtr->segTablePtr, 
  1335.         (Address) (contextPtr->map + segDataPtr->offset),
  1336.         segDataPtr->numSegs);
  1337.     if (vmPtr->sharedSegs != (List_Links *)NIL) {
  1338.         Vm_SegProcList *segList;
  1339.         LIST_FORALL(vmPtr->sharedSegs,(List_Links *)segList) {
  1340.         segDataPtr = segList->segTabPtr->segPtr->machPtr;
  1341.         bcopy((Address)segDataPtr->segTablePtr, 
  1342.             (Address) (contextPtr->map+PageToSeg(segList->offset)),
  1343.             segDataPtr->numSegs);
  1344.         }
  1345.     }
  1346.     if (vmPtr->machPtr->mapSegPtr != (struct Vm_Segment *)NIL) {
  1347.         contextPtr->map[MAP_SEG_NUM] = vmPtr->machPtr->mapHardSeg;
  1348.     } else {
  1349.         contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1350.     }
  1351.     /*
  1352.      * Push map out to hardware.
  1353.      */
  1354.     VmMachSegMapCopy((Address)contextPtr->map, 0, (int)mach_KernStart);
  1355.     } else {
  1356.     VmMachSetContextReg(contextPtr->context);
  1357.     }
  1358.     List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  1359. }
  1360.  
  1361.  
  1362. /*
  1363.  * ----------------------------------------------------------------------------
  1364.  *
  1365.  * Vm_FreeContext --
  1366.  *
  1367.  *      Free the given context.
  1368.  *
  1369.  * Results:
  1370.  *      None.
  1371.  *
  1372.  * Side effects:
  1373.  *      The context table and context lists are modified.
  1374.  *
  1375.  * ----------------------------------------------------------------------------
  1376.  */
  1377. void
  1378. VmMach_FreeContext(procPtr)
  1379.     register    Proc_ControlBlock    *procPtr;
  1380. {
  1381.     register    VmMach_Context    *contextPtr;
  1382.     register    VmMach_ProcData    *machPtr;
  1383.  
  1384.     MASTER_LOCK(vmMachMutexPtr);
  1385.  
  1386.     machPtr = procPtr->vmPtr->machPtr;
  1387.     contextPtr = machPtr->contextPtr;
  1388.     if (contextPtr == (VmMach_Context *)NIL ||
  1389.         contextPtr->context == VMMACH_KERN_CONTEXT) {
  1390.     MASTER_UNLOCK(vmMachMutexPtr);
  1391.     return;
  1392.     }
  1393.     List_Move((List_Links *)contextPtr, LIST_ATFRONT(contextList));
  1394.     contextPtr->flags = 0;
  1395.     machPtr->contextPtr = (VmMach_Context *)NIL;
  1396.  
  1397.     MASTER_UNLOCK(vmMachMutexPtr);
  1398. }
  1399.  
  1400.  
  1401. /*
  1402.  * ----------------------------------------------------------------------------
  1403.  *
  1404.  * VmMach_ReinitContext --
  1405.  *
  1406.  *      Free the current context and set up another one.  This is called
  1407.  *    by routines such as Proc_Exec that add things to the context and
  1408.  *    then have to abort or start a process running with a new image.
  1409.  *
  1410.  * Results:
  1411.  *      None.
  1412.  *
  1413.  * Side effects:
  1414.  *      The context table and context lists are modified.
  1415.  *
  1416.  * ----------------------------------------------------------------------------
  1417.  */
  1418. void
  1419. VmMach_ReinitContext(procPtr)
  1420.     register    Proc_ControlBlock    *procPtr;
  1421. {
  1422.     VmMach_FreeContext(procPtr);
  1423.     MASTER_LOCK(vmMachMutexPtr);
  1424.     procPtr->vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  1425.     SetupContext(procPtr);
  1426.     MASTER_UNLOCK(vmMachMutexPtr);
  1427. }
  1428.  
  1429. #ifdef sun2
  1430.  
  1431. static int     allocatedPMEG;
  1432. static VmMachPTE intelSavedPTE;        /* The page table entry that is stored
  1433.                      * at the address that the intel page
  1434.                      * has to overwrite. */
  1435. static unsigned int intelPage;        /* The page frame that was allocated.*/
  1436. #endif
  1437.  
  1438.  
  1439. /*
  1440.  * ----------------------------------------------------------------------------
  1441.  *
  1442.  * VmMach_MapIntelPage --
  1443.  *
  1444.  *      Allocate and validate a page for the Intel Ethernet chip.  This routine
  1445.  *    is required in order to initialize the chip.  The chip expects 
  1446.  *    certain stuff to be at a specific virtual address when it is 
  1447.  *    initialized.  This routine sets things up so that the expected
  1448.  *    virtual address is accessible.
  1449.  *
  1450.  * Results:
  1451.  *      None.
  1452.  *
  1453.  * Side effects:
  1454.  *      The old pte stored at the virtual address and the page frame that is
  1455.  *    allocated are stored in static globals.
  1456.  *
  1457.  * ----------------------------------------------------------------------------
  1458.  */
  1459. /*ARGSUSED*/
  1460. void
  1461. VmMach_MapIntelPage(virtAddr) 
  1462.     Address    virtAddr; /* Virtual address where a page has to be validated
  1463.                  at. */
  1464. {
  1465. #ifdef sun2
  1466.     VmMachPTE        pte;
  1467.     int            pmeg;
  1468.  
  1469.     /*
  1470.      * See if there is a PMEG already.  If not allocate one.
  1471.      */
  1472.  
  1473.     pmeg = VmMachGetSegMap(virtAddr);
  1474.     if (pmeg == VMMACH_INV_PMEG) {
  1475.     MASTER_LOCK(vmMachMutexPtr);
  1476.     allocatedPMEG = PMEGGet(vm_SysSegPtr, 
  1477.                 (unsigned)virtAddr >> VMMACH_SEG_SHIFT,
  1478.                 PMEG_DONT_ALLOC);
  1479.     MASTER_UNLOCK(vmMachMutexPtr);
  1480.     VmMachSetSegMap(virtAddr, allocatedPMEG);
  1481.     } else {
  1482.     allocatedPMEG = VMMACH_INV_PMEG;
  1483.     intelSavedPTE = VmMachGetPageMap(virtAddr);
  1484.     }
  1485.  
  1486.     /*
  1487.      * Set up the page table entry.
  1488.      */
  1489.     intelPage = Vm_KernPageAllocate();
  1490.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(intelPage);
  1491.     VmMachSetPageMap(virtAddr, pte);
  1492. #endif
  1493. }
  1494.  
  1495.  
  1496. /*
  1497.  * ----------------------------------------------------------------------------
  1498.  *
  1499.  * Vm_UnmapIntelPage --
  1500.  *
  1501.  *      Deallocate and invalidate a page for the intel chip.  This is a special
  1502.  *    case routine that is only for the intel ethernet chip.
  1503.  *
  1504.  * Results:
  1505.  *      None.
  1506.  *
  1507.  * Side effects:
  1508.  *      The hardware segment table associated with the segment
  1509.  *      is modified to invalidate the page.
  1510.  *
  1511.  * ----------------------------------------------------------------------------
  1512.  */
  1513. /*ARGSUSED*/
  1514. void
  1515. VmMach_UnmapIntelPage(virtAddr) 
  1516.     Address    virtAddr;
  1517. {
  1518. #ifdef sun2
  1519.     if (allocatedPMEG != VMMACH_INV_PMEG) {
  1520.     /*
  1521.      * Free up the PMEG.
  1522.      */
  1523.     VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  1524.     VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1525.  
  1526.     MASTER_LOCK(vmMachMutexPtr);
  1527.  
  1528.     PMEGFree(allocatedPMEG);
  1529.  
  1530.     MASTER_UNLOCK(vmMachMutexPtr);
  1531.     } else {
  1532.     /*
  1533.      * Restore the saved pte and free the allocated page.
  1534.      */
  1535.     VmMachSetPageMap(virtAddr, intelSavedPTE);
  1536.     }
  1537.     Vm_KernPageFree(intelPage);
  1538. #endif
  1539. }
  1540.  
  1541. #ifdef sun3
  1542.  
  1543. static Address        netMemAddr;
  1544. static unsigned int    netLastPage;
  1545.  
  1546.  
  1547. /*
  1548.  * ----------------------------------------------------------------------------
  1549.  *
  1550.  * InitNetMem --
  1551.  *
  1552.  *      Initialize the memory mappings for the network.
  1553.  *
  1554.  * Results:
  1555.  *      None.
  1556.  *
  1557.  * Side effects:
  1558.  *      PMEGS are allocated and initialized.
  1559.  *
  1560.  * ----------------------------------------------------------------------------
  1561.  */
  1562. static void
  1563. InitNetMem()
  1564. {
  1565.     unsigned char        pmeg;
  1566.     register unsigned char    *segTablePtr;
  1567.     int                i;
  1568.     int                segNum;
  1569.     Address            virtAddr;
  1570.  
  1571.     /*
  1572.      * Allocate two pmegs, one for memory and one for mapping.
  1573.      */
  1574.     segNum = VMMACH_NET_MAP_START >> VMMACH_SEG_SHIFT;
  1575.     for (i = 0, virtAddr = (Address)VMMACH_NET_MAP_START,
  1576.         segTablePtr = GetHardSegPtr(vm_SysSegPtr->machPtr, segNum);
  1577.      i < 2;
  1578.          i++, virtAddr += VMMACH_SEG_SIZE, segNum++) {
  1579.     pmeg = VmMachGetSegMap(virtAddr);
  1580.     if (pmeg == VMMACH_INV_PMEG) {
  1581.         *(segTablePtr + i) = PMEGGet(vm_SysSegPtr, segNum, PMEG_DONT_ALLOC);
  1582.         VmMachSetSegMap(virtAddr, *(segTablePtr + i));
  1583.     }
  1584.     }
  1585.     /*
  1586.      * Propagate the new pmeg mappings to all contexts.
  1587.      */
  1588.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1589.     if (i == VMMACH_KERN_CONTEXT) {
  1590.         continue;
  1591.     }
  1592.     VmMachSetContextReg(i);
  1593.     VmMachSetSegMap((Address)VMMACH_NET_MAP_START, *segTablePtr);
  1594.     VmMachSetSegMap((Address)(VMMACH_NET_MAP_START + VMMACH_SEG_SIZE),
  1595.             *(segTablePtr + 1));
  1596.     }
  1597.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  1598.     netMemAddr = (Address)VMMACH_NET_MEM_START;
  1599.     netLastPage = ((unsigned)(VMMACH_NET_MEM_START) >> VMMACH_PAGE_SHIFT) - 1;
  1600. }
  1601.  
  1602. /*
  1603.  * ----------------------------------------------------------------------------
  1604.  *
  1605.  * VmMach_NetMemAlloc --
  1606.  *
  1607.  *      Allocate physical memory for a network driver.
  1608.  *
  1609.  * Results:
  1610.  *      The address where the memory is allocated at.
  1611.  *
  1612.  * Side effects:
  1613.  *      Memory allocated.
  1614.  *
  1615.  * ----------------------------------------------------------------------------
  1616.  */
  1617. Address
  1618. VmMach_NetMemAlloc(numBytes)
  1619.     int    numBytes;    /* Number of bytes of memory to allocated. */
  1620. {
  1621.     VmMachPTE    pte;
  1622.     Address    retAddr;
  1623.     Address    maxAddr;
  1624.     Address    virtAddr;
  1625.     static Boolean initialized = FALSE;
  1626.  
  1627.     if (!initialized) {
  1628.     InitNetMem();
  1629.     initialized = TRUE;
  1630.     }
  1631.  
  1632.     retAddr = netMemAddr;
  1633.     netMemAddr += (numBytes + 3) & ~3;
  1634.     /*
  1635.      * Panic if we are out of memory.  We are out of memory if we have filled
  1636.      * up a whole PMEG minus one page.  We have to leave one page at the
  1637.      * end because this is used to initialize the INTEL chip.
  1638.      */
  1639.     if (netMemAddr > (Address) (VMMACH_NET_MEM_START + VMMACH_SEG_SIZE - 
  1640.                 VMMACH_PAGE_SIZE)) {
  1641.     panic("VmMach_NetMemAlloc: Out of network memory\n");
  1642.     }
  1643.  
  1644.     maxAddr = (Address) ((netLastPage + 1) * VMMACH_PAGE_SIZE - 1);
  1645.  
  1646.     /*
  1647.      * Add new pages to the virtual address space until we have added enough
  1648.      * to handle this memory request.
  1649.      */
  1650.     while (netMemAddr - 1 > maxAddr) {
  1651.     maxAddr += VMMACH_PAGE_SIZE;
  1652.     netLastPage++;
  1653.     virtAddr = (Address) (netLastPage << VMMACH_PAGE_SHIFT);
  1654.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  1655.           VirtToPhysPage(Vm_KernPageAllocate());
  1656.     SET_ALL_PAGE_MAP(virtAddr, pte);
  1657.     }
  1658.  
  1659.     return(retAddr);
  1660. }
  1661.  
  1662.  
  1663. /*
  1664.  *----------------------------------------------------------------------
  1665.  *
  1666.  * VmMach_NetMapPacket --
  1667.  *
  1668.  *    Map the packet pointed to by the scatter-gather array.
  1669.  *
  1670.  * Results:
  1671.  *    None.
  1672.  *
  1673.  * Side effects:
  1674.  *    The outScatGathArray is filled in with pointers to where the
  1675.  *    packet was mapped in.
  1676.  *
  1677.  *----------------------------------------------------------------------
  1678.  */
  1679. void
  1680. VmMach_NetMapPacket(inScatGathPtr, scatGathLength, outScatGathPtr)
  1681.     register Net_ScatterGather    *inScatGathPtr;
  1682.     register int        scatGathLength;
  1683.     register Net_ScatterGather    *outScatGathPtr;
  1684. {
  1685.     register Address    mapAddr;
  1686.     register Address    endAddr;
  1687.  
  1688.     for (mapAddr = (Address)VMMACH_NET_MAP_START;
  1689.          scatGathLength > 0;
  1690.      scatGathLength--, inScatGathPtr++, outScatGathPtr++) {
  1691.     outScatGathPtr->length = inScatGathPtr->length;
  1692.     if (inScatGathPtr->length == 0) {
  1693.         continue;
  1694.     }
  1695.     /*
  1696.      * Map the piece of the packet in.  Note that we know that a packet
  1697.      * piece is no longer than 1536 bytes so we know that we will need
  1698.      * at most two page table entries to map a piece in.
  1699.      */
  1700.     VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  1701.     outScatGathPtr->bufAddr = 
  1702.         mapAddr + ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK);
  1703.     mapAddr += VMMACH_PAGE_SIZE_INT;
  1704.     endAddr = inScatGathPtr->bufAddr + inScatGathPtr->length - 1;
  1705.     if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  1706.         ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  1707.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  1708.         mapAddr += VMMACH_PAGE_SIZE_INT;
  1709.     }
  1710.     }
  1711. }
  1712.  
  1713. #endif
  1714.  
  1715.  
  1716. /*
  1717.  *----------------------------------------------------------------------
  1718.  *
  1719.  * VmMach_VirtAddrParse --
  1720.  *
  1721.  *    See if the given address falls into the special mapping segment.
  1722.  *    If so parse it for our caller.
  1723.  *
  1724.  * Results:
  1725.  *    TRUE if the address fell into the special mapping segment, FALSE
  1726.  *    otherwise.
  1727.  *
  1728.  * Side effects:
  1729.  *    *transVirtAddrPtr may be filled in.
  1730.  *
  1731.  *----------------------------------------------------------------------
  1732.  */
  1733. Boolean
  1734. VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  1735.     Proc_ControlBlock        *procPtr;
  1736.     Address            virtAddr;
  1737.     register    Vm_VirtAddr    *transVirtAddrPtr;
  1738. {
  1739.     Address    origVirtAddr;
  1740.     Boolean    retVal;
  1741.  
  1742.     if (virtAddr >= (Address)VMMACH_MAP_SEG_ADDR && 
  1743.         virtAddr < (Address)mach_KernStart) {
  1744.     /*
  1745.      * The address falls into the special mapping segment.  Translate
  1746.      * the address back to the segment that it falls into.
  1747.      */
  1748.     transVirtAddrPtr->segPtr = procPtr->vmPtr->machPtr->mapSegPtr;
  1749.     origVirtAddr = 
  1750.         (Address)(procPtr->vmPtr->machPtr->mapHardSeg << VMMACH_SEG_SHIFT);
  1751.     transVirtAddrPtr->sharedPtr = procPtr->vmPtr->machPtr->sharedPtr;
  1752.     if (transVirtAddrPtr->segPtr->type == VM_SHARED) {
  1753.         origVirtAddr += ((segOffset(transVirtAddrPtr)-
  1754.             transVirtAddrPtr->segPtr->offset)
  1755.             >>(VMMACH_SEG_SHIFT-VMMACH_PAGE_SHIFT))
  1756.             << VMMACH_SEG_SHIFT;
  1757.     }
  1758.     if (debugVmStubs) {
  1759.         printf("segOffset = %x, offset = %x, mapHardSeg = %x\n",
  1760.             segOffset(transVirtAddrPtr),
  1761.             transVirtAddrPtr->segPtr->offset,
  1762.             procPtr->vmPtr->machPtr->mapHardSeg);
  1763.     }
  1764.     origVirtAddr += (unsigned int)virtAddr & (VMMACH_SEG_SIZE - 1);
  1765.     transVirtAddrPtr->page = (unsigned) (origVirtAddr) >> VMMACH_PAGE_SHIFT;
  1766.     transVirtAddrPtr->offset = (unsigned)virtAddr & VMMACH_OFFSET_MASK;
  1767.     transVirtAddrPtr->flags = USING_MAPPED_SEG;
  1768.     retVal = TRUE;
  1769.     } else {
  1770.     retVal = FALSE;
  1771.     }
  1772.     return(retVal);
  1773. }
  1774.  
  1775. static void    WriteHardMapSeg();
  1776.  
  1777.  
  1778. /*
  1779.  *----------------------------------------------------------------------
  1780.  *
  1781.  * VmMach_CopyInProc --
  1782.  *
  1783.  *    Copy from another processes address space into the current address
  1784.  *    space.   This is done by mapping the other processes segment into
  1785.  *    the current VAS and then doing the copy.  It assumed that this 
  1786.  *    routine is called with the source process locked such that its
  1787.  *    VM will not go away while we are doing this copy.
  1788.  *
  1789.  * Results:
  1790.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  1791.  *
  1792.  * Side effects:
  1793.  *    What toAddr points to is modified.
  1794.  *
  1795.  *----------------------------------------------------------------------
  1796.  */
  1797. /*ARGSUSED*/
  1798. ReturnStatus
  1799. VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr, virtAddrPtr,
  1800.           toAddr, toKernel)
  1801.     int     numBytes;        /* The maximum number of bytes to 
  1802.                        copy in. */
  1803.     Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  1804.     Address        fromAddr;    /* The address to copy from */
  1805.     Vm_VirtAddr        *virtAddrPtr;
  1806.     Address        toAddr;        /* The address to copy to */
  1807.     Boolean        toKernel;    /* This copy is happening to the
  1808.                      * kernel's address space. */
  1809. {
  1810.     ReturnStatus        status = SUCCESS;
  1811.     register VmMach_ProcData    *machPtr;
  1812.     Proc_ControlBlock        *toProcPtr;
  1813.     int                segOffset;
  1814.     int                bytesToCopy;
  1815.  
  1816.     toProcPtr = Proc_GetCurrentProc();
  1817.     machPtr = toProcPtr->vmPtr->machPtr;
  1818.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  1819.     machPtr->mapHardSeg = (unsigned int) (fromAddr) >> VMMACH_SEG_SHIFT;
  1820.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  1821.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  1822.     /*
  1823.      * Mangle the segment offset so that it matches the offset
  1824.      * of the mapped segment.
  1825.      */
  1826.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  1827.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  1828.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  1829.     }
  1830.     /*
  1831.      * Do a hardware segments worth at a time until done.
  1832.      */
  1833.     while (numBytes > 0 && status == SUCCESS) {
  1834.     segOffset = (unsigned int)fromAddr & (VMMACH_SEG_SIZE - 1);
  1835.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  1836.     if (bytesToCopy > numBytes) {
  1837.         bytesToCopy = numBytes;
  1838.     }
  1839.     /*
  1840.      * Push out the hardware segment.
  1841.      */
  1842.     WriteHardMapSeg(machPtr);
  1843.     /*
  1844.      * Do the copy.
  1845.      */
  1846.     toProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  1847.     status = VmMachDoCopy(bytesToCopy,
  1848.                   (Address)(VMMACH_MAP_SEG_ADDR + segOffset),
  1849.                   toAddr);
  1850.     toProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  1851.     if (status == SUCCESS) {
  1852.         numBytes -= bytesToCopy;
  1853.         fromAddr += bytesToCopy;
  1854.         toAddr += bytesToCopy;
  1855.     } else {
  1856.         status = SYS_ARG_NOACCESS;
  1857.     }
  1858.     /*
  1859.      * Zap the hardware segment.
  1860.      */
  1861.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  1862.     machPtr->mapHardSeg++;
  1863.     }
  1864.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1865.     return(status);
  1866. }
  1867.  
  1868.  
  1869. /*
  1870.  *----------------------------------------------------------------------
  1871.  *
  1872.  * VmMach_CopyOutProc --
  1873.  *
  1874.  *    Copy from the current VAS to another processes VAS.  This is done by 
  1875.  *    mapping the other processes segment into the current VAS and then 
  1876.  *    doing the copy.  It assumed that this routine is called with the dest
  1877.  *    process locked such that its VM will not go away while we are doing
  1878.  *    the copy.
  1879.  *
  1880.  * Results:
  1881.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  1882.  *
  1883.  * Side effects:
  1884.  *    What toAddr points to is modified.
  1885.  *
  1886.  *----------------------------------------------------------------------
  1887.  */
  1888. /*ARGSUSED*/
  1889. ReturnStatus
  1890. VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr,
  1891.            virtAddrPtr)
  1892.     int         numBytes;    /* The maximum number of bytes to 
  1893.                        copy in. */
  1894.     Address        fromAddr;    /* The address to copy from */
  1895.     Boolean        fromKernel;    /* This copy is happening to the
  1896.                      * kernel's address space. */
  1897.     Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  1898.     Address        toAddr;        /* The address to copy to */
  1899.     Vm_VirtAddr        *virtAddrPtr;
  1900. {
  1901.     ReturnStatus        status = SUCCESS;
  1902.     register VmMach_ProcData    *machPtr;
  1903.     Proc_ControlBlock        *fromProcPtr;
  1904.     int                segOffset;
  1905.     int                bytesToCopy;
  1906.  
  1907.  
  1908.     fromProcPtr = Proc_GetCurrentProc();
  1909.     machPtr = fromProcPtr->vmPtr->machPtr;
  1910.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  1911.     machPtr->mapHardSeg = (unsigned int) (toAddr) >> VMMACH_SEG_SHIFT;
  1912.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  1913.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  1914.     /*
  1915.      * Mangle the segment offset so that it matches the offset
  1916.      * of the mapped segment.
  1917.      */
  1918.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  1919.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  1920.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  1921.     }
  1922.     /*
  1923.      * Do a hardware segments worth at a time until done.
  1924.      */
  1925.     while (numBytes > 0 && status == SUCCESS) {
  1926.     segOffset = (unsigned int)toAddr & (VMMACH_SEG_SIZE - 1);
  1927.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  1928.     if (bytesToCopy > numBytes) {
  1929.         bytesToCopy = numBytes;
  1930.     }
  1931.     /*
  1932.      * Push out the hardware segment.
  1933.      */
  1934.     WriteHardMapSeg(machPtr);
  1935.     /*
  1936.      * Do the copy.
  1937.      */
  1938.     fromProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  1939.     status = VmMachDoCopy(bytesToCopy, fromAddr,
  1940.               (Address) (VMMACH_MAP_SEG_ADDR + segOffset));
  1941.     fromProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  1942.     if (status == SUCCESS) {
  1943.         numBytes -= bytesToCopy;
  1944.         fromAddr += bytesToCopy;
  1945.         toAddr += bytesToCopy;
  1946.     } else {
  1947.         status = SYS_ARG_NOACCESS;
  1948.     }
  1949.     /*
  1950.      * Zap the hardware segment.
  1951.      */
  1952.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  1953.  
  1954.     machPtr->mapHardSeg++;
  1955.     }
  1956.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1957.     return(status);
  1958. }
  1959.  
  1960.  
  1961. /*
  1962.  *----------------------------------------------------------------------
  1963.  *
  1964.  * WriteHardMapSeg --
  1965.  *
  1966.  *    Push the hardware segment map entry out to the hardware for the
  1967.  *    given mapped segment.
  1968.  *
  1969.  * Results:
  1970.  *    None.
  1971.  *
  1972.  * Side effects:
  1973.  *    Hardware segment modified.
  1974.  *
  1975.  *----------------------------------------------------------------------
  1976.  */
  1977. static void
  1978. WriteHardMapSeg(machPtr)
  1979.     VmMach_ProcData    *machPtr;
  1980. {
  1981.     MASTER_LOCK(vmMachMutexPtr);
  1982.  
  1983.     if (machPtr->contextPtr != (VmMach_Context *) NIL) {
  1984.         machPtr->contextPtr->map[MAP_SEG_NUM] =
  1985.             (int)*GetHardSegPtr(machPtr->mapSegPtr->machPtr,
  1986.             machPtr->mapHardSeg);
  1987.     }
  1988.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, 
  1989.      *GetHardSegPtr(machPtr->mapSegPtr->machPtr, machPtr->mapHardSeg));
  1990.  
  1991.     MASTER_UNLOCK(vmMachMutexPtr);
  1992. }
  1993.  
  1994.  
  1995. /*
  1996.  *----------------------------------------------------------------------
  1997.  *
  1998.  * VmMach_SetSegProt --
  1999.  *
  2000.  *    Change the protection in the page table for the given range of bytes
  2001.  *    for the given segment.
  2002.  *
  2003.  * Results:
  2004.  *    None.
  2005.  *
  2006.  * Side effects:
  2007.  *    Page table may be modified for the segment.
  2008.  *
  2009.  *----------------------------------------------------------------------
  2010.  */
  2011. void
  2012. VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable)
  2013.     register Vm_Segment        *segPtr;    /* Segment to change protection
  2014.                            for. */
  2015.     register int        firstPage;  /* First page to set protection
  2016.                          * for. */
  2017.     int                lastPage;   /* First page to set protection
  2018.                          * for. */
  2019.     Boolean            makeWriteable;/* TRUE => make the pages 
  2020.                            *     writable.
  2021.                            * FALSE => make readable only.*/
  2022. {
  2023.     register    VmMachPTE    pte;
  2024.     register    Address        virtAddr;
  2025.     register    unsigned char    *pmegNumPtr;
  2026.     register    PMEG        *pmegPtr;
  2027.     register    Boolean        skipSeg = FALSE;
  2028.     Boolean            nextSeg = TRUE;
  2029.     Address            tVirtAddr;
  2030.     Address            pageVirtAddr;
  2031.     int                i;
  2032.  
  2033.     MASTER_LOCK(vmMachMutexPtr);
  2034.  
  2035.     pmegNumPtr = GetHardSegPtr(segPtr->machPtr, PageToSeg(firstPage)) - 1;
  2036.     virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  2037.     while (firstPage <= lastPage) {
  2038.     if (nextSeg) {
  2039.         pmegNumPtr++;
  2040.         if (*pmegNumPtr != VMMACH_INV_PMEG) {
  2041.         pmegPtr = &pmegArray[*pmegNumPtr];
  2042.         if (pmegPtr->pageCount != 0) {
  2043.             VmMachSetSegMap(vmMachPTESegAddr, *pmegNumPtr);
  2044.             skipSeg = FALSE;
  2045.         } else {
  2046.             skipSeg = TRUE;
  2047.         }
  2048.         } else {
  2049.         skipSeg = TRUE;
  2050.         }
  2051.         nextSeg = FALSE;
  2052.     }
  2053.     if (!skipSeg) {
  2054.         /*
  2055.          * Change the hardware page table.
  2056.          */
  2057.         tVirtAddr =
  2058.         ((unsigned int)virtAddr & VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2059.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++) {
  2060.         pageVirtAddr = tVirtAddr + i * VMMACH_PAGE_SIZE_INT;
  2061.         pte = VmMachGetPageMap(pageVirtAddr);
  2062.         if (pte & VMMACH_RESIDENT_BIT) {
  2063.             pte &= ~VMMACH_PROTECTION_FIELD;
  2064.             pte |= makeWriteable ? VMMACH_URW_PROT : VMMACH_UR_PROT;
  2065.             VmMachSetPageMap(pageVirtAddr, pte);
  2066.         }
  2067.         }
  2068.         virtAddr += VMMACH_PAGE_SIZE;
  2069.         firstPage++;
  2070.         if (((unsigned int)virtAddr & VMMACH_PAGE_MASK) == 0) {
  2071.         nextSeg = TRUE;
  2072.         }
  2073.     } else {
  2074.         int    segNum;
  2075.  
  2076.         segNum = PageToSeg(firstPage) + 1;
  2077.         firstPage = SegToPage(segNum);
  2078.         virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  2079.         nextSeg = TRUE;
  2080.     }
  2081.     }
  2082.  
  2083.     MASTER_UNLOCK(vmMachMutexPtr);
  2084. }
  2085.  
  2086.  
  2087. /*
  2088.  *----------------------------------------------------------------------
  2089.  *
  2090.  * VmMach_SetPageProt --
  2091.  *
  2092.  *    Set the protection in hardware and software for the given virtual
  2093.  *    page.
  2094.  *
  2095.  * Results:
  2096.  *    None.
  2097.  *
  2098.  * Side effects:
  2099.  *    Page table may be modified for the segment.
  2100.  *
  2101.  *----------------------------------------------------------------------
  2102.  */
  2103. void
  2104. VmMach_SetPageProt(virtAddrPtr, softPTE)
  2105.     register    Vm_VirtAddr    *virtAddrPtr;    /* The virtual page to set the
  2106.                          * protection for.*/
  2107.     Vm_PTE            softPTE;    /* Software pte. */
  2108. {
  2109.     register    VmMachPTE     hardPTE;
  2110.     register    VmMach_SegData    *machPtr;
  2111.     Address               virtAddr;
  2112.     int                pmegNum;
  2113.     int                i;
  2114.  
  2115.     MASTER_LOCK(vmMachMutexPtr);
  2116.  
  2117.     machPtr = virtAddrPtr->segPtr->machPtr;
  2118.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2119.         virtAddrPtr));
  2120.     if (pmegNum != VMMACH_INV_PMEG) {
  2121.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  2122.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;    
  2123.     for (i = 0; 
  2124.          i < VMMACH_CLUSTER_SIZE; 
  2125.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2126.         hardPTE = VmMachReadPTE(pmegNum, virtAddr);
  2127.         hardPTE &= ~VMMACH_PROTECTION_FIELD;
  2128.         hardPTE |= (softPTE & (VM_COW_BIT | VM_READ_ONLY_PROT)) ? 
  2129.                     VMMACH_UR_PROT : VMMACH_URW_PROT;
  2130.         VmMachWritePTE(pmegNum, virtAddr, hardPTE);
  2131.     }
  2132.     }
  2133.  
  2134.     MASTER_UNLOCK(vmMachMutexPtr);
  2135. }
  2136.  
  2137.  
  2138. /*
  2139.  * ----------------------------------------------------------------------------
  2140.  *
  2141.  * VmMach_AllocCheck --
  2142.  *
  2143.  *      Determine if this page can be reallocated.  A page can be reallocated
  2144.  *    if it has not been referenced or modified.
  2145.  *  
  2146.  * Results:
  2147.  *      None.
  2148.  *
  2149.  * Side effects:
  2150.  *      The given page will be invalidated in the hardware if it has not
  2151.  *    been referenced and *refPtr and *modPtr will have the hardware 
  2152.  *    reference and modify bits or'd in.
  2153.  *
  2154.  * ----------------------------------------------------------------------------
  2155.  */
  2156. void
  2157. VmMach_AllocCheck(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  2158.     register    Vm_VirtAddr    *virtAddrPtr;
  2159.     unsigned    int        virtFrameNum;
  2160.     register    Boolean        *refPtr;
  2161.     register    Boolean        *modPtr;
  2162. {
  2163.     register VmMach_SegData    *machPtr;
  2164.     register VmMachPTE         hardPTE;  
  2165.     int                pmegNum; 
  2166.     Address            virtAddr;
  2167.     int                i;
  2168.     int                origMod;
  2169.  
  2170.     MASTER_LOCK(vmMachMutexPtr);
  2171.  
  2172.     origMod = *modPtr;
  2173.  
  2174.     *refPtr |= refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  2175.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  2176.     if (!*refPtr || !*modPtr) {
  2177.     machPtr = virtAddrPtr->segPtr->machPtr;
  2178.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2179.         virtAddrPtr));
  2180.     if (pmegNum != VMMACH_INV_PMEG) {
  2181.         hardPTE = 0;
  2182.         virtAddr = 
  2183.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  2184.             vmMachPTESegAddr;
  2185.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  2186.         hardPTE |= VmMachReadPTE(pmegNum, 
  2187.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  2188.         }
  2189.         *refPtr |= hardPTE & VMMACH_REFERENCED_BIT;
  2190.         *modPtr |= hardPTE & VMMACH_MODIFIED_BIT;
  2191.     }
  2192.     }
  2193.     if (!*refPtr) {
  2194.     /*
  2195.      * Invalidate the page so that it will force a fault if it is
  2196.      * referenced.  Since our caller has blocked all faults on this
  2197.      * page, by invalidating it we can guarantee that the reference and
  2198.      * modify information that we are returning will be valid until
  2199.      * our caller reenables faults on this page.
  2200.      */
  2201.     PageInvalidate(virtAddrPtr, virtFrameNum, FALSE);
  2202.  
  2203.     if (origMod && !*modPtr) {
  2204.         /*
  2205.          * This page had the modify bit set in software but not in
  2206.          * hardware.
  2207.          */
  2208.         vmStat.notHardModPages++;
  2209.     }
  2210.     }
  2211.     *modPtr |= origMod;
  2212.  
  2213.     MASTER_UNLOCK(vmMachMutexPtr);
  2214.  
  2215. }
  2216.  
  2217.  
  2218. /*
  2219.  * ----------------------------------------------------------------------------
  2220.  *
  2221.  * VmMach_GetRefModBits --
  2222.  *
  2223.  *      Pull the reference and modified bits out of hardware.
  2224.  *  
  2225.  * Results:
  2226.  *      None.
  2227.  *
  2228.  * Side effects:
  2229.  *      
  2230.  *
  2231.  * ----------------------------------------------------------------------------
  2232.  */
  2233. void
  2234. VmMach_GetRefModBits(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  2235.     register    Vm_VirtAddr    *virtAddrPtr;
  2236.     unsigned    int        virtFrameNum;
  2237.     register    Boolean        *refPtr;
  2238.     register    Boolean        *modPtr;
  2239. {
  2240.     register VmMach_SegData    *machPtr;
  2241.     register VmMachPTE         hardPTE;  
  2242.     int                pmegNum; 
  2243.     Address            virtAddr;
  2244.     int                i;
  2245.  
  2246.     MASTER_LOCK(vmMachMutexPtr);
  2247.  
  2248.     *refPtr = refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  2249.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  2250.     if (!*refPtr || !*modPtr) {
  2251.     machPtr = virtAddrPtr->segPtr->machPtr;
  2252.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2253.         virtAddrPtr));
  2254.     if (pmegNum != VMMACH_INV_PMEG) {
  2255.         hardPTE = 0;
  2256.         virtAddr = 
  2257.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  2258.             vmMachPTESegAddr;
  2259.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  2260.         hardPTE |= VmMachReadPTE(pmegNum, 
  2261.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  2262.         }
  2263.         if (!*refPtr) {
  2264.         *refPtr = hardPTE & VMMACH_REFERENCED_BIT;
  2265.         }
  2266.         if (!*modPtr) {
  2267.         *modPtr = hardPTE & VMMACH_MODIFIED_BIT;
  2268.         }
  2269.     }
  2270.     }
  2271.  
  2272.     MASTER_UNLOCK(vmMachMutexPtr);
  2273.  
  2274. }
  2275.  
  2276.  
  2277. /*
  2278.  * ----------------------------------------------------------------------------
  2279.  *
  2280.  * VmMach_ClearRefBit --
  2281.  *
  2282.  *      Clear the reference bit at the given virtual address.
  2283.  *
  2284.  * Results:
  2285.  *      None.
  2286.  *
  2287.  * Side effects:
  2288.  *      Hardware reference bit cleared.
  2289.  *
  2290.  * ----------------------------------------------------------------------------
  2291.  */
  2292. void
  2293. VmMach_ClearRefBit(virtAddrPtr, virtFrameNum)
  2294.     register    Vm_VirtAddr    *virtAddrPtr;
  2295.     unsigned     int        virtFrameNum;
  2296. {
  2297.     register    VmMach_SegData    *machPtr;
  2298.     int                pmegNum;
  2299.     Address            virtAddr;
  2300.     int                i;
  2301.     VmMachPTE            pte;
  2302.  
  2303.     MASTER_LOCK(vmMachMutexPtr);
  2304.  
  2305.     refModMap[virtFrameNum] &= ~VMMACH_REFERENCED_BIT;
  2306.     machPtr = virtAddrPtr->segPtr->machPtr;
  2307.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2308.         virtAddrPtr));
  2309.     if (pmegNum != VMMACH_INV_PMEG) {
  2310.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  2311.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2312.     for (i = 0; 
  2313.          i < VMMACH_CLUSTER_SIZE;
  2314.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2315.         pte = VmMachReadPTE(pmegNum, virtAddr);
  2316.         pte &= ~VMMACH_REFERENCED_BIT;
  2317.         VmMachWritePTE(pmegNum, virtAddr, pte);
  2318.     }
  2319.     }
  2320.  
  2321.     MASTER_UNLOCK(vmMachMutexPtr);
  2322. }
  2323.  
  2324.  
  2325. /*
  2326.  * ----------------------------------------------------------------------------
  2327.  *
  2328.  * VmMach_ClearModBit --
  2329.  *
  2330.  *      Clear the modified bit at the given virtual address.
  2331.  *
  2332.  * Results:
  2333.  *      None.
  2334.  *
  2335.  * Side effects:
  2336.  *      Hardware modified bit cleared.
  2337.  *
  2338.  * ----------------------------------------------------------------------------
  2339.  */
  2340. void
  2341. VmMach_ClearModBit(virtAddrPtr, virtFrameNum)
  2342.     register    Vm_VirtAddr    *virtAddrPtr;
  2343.     unsigned    int        virtFrameNum;
  2344. {
  2345.     register    VmMach_SegData    *machPtr;
  2346.     int                pmegNum;
  2347.     Address            virtAddr;
  2348.     int                i;
  2349.     Vm_PTE            pte;
  2350.  
  2351.     MASTER_LOCK(vmMachMutexPtr);
  2352.  
  2353.     refModMap[virtFrameNum] &= ~VMMACH_MODIFIED_BIT;
  2354.     machPtr = virtAddrPtr->segPtr->machPtr;
  2355.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2356.         virtAddrPtr));
  2357.     if (pmegNum != VMMACH_INV_PMEG) {
  2358.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  2359.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2360.     for (i = 0; 
  2361.          i < VMMACH_CLUSTER_SIZE; 
  2362.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2363.         pte = VmMachReadPTE(pmegNum, virtAddr);
  2364.         pte &= ~VMMACH_MODIFIED_BIT;
  2365.         VmMachWritePTE(pmegNum, virtAddr, pte);
  2366.     }
  2367.     }
  2368.  
  2369.     MASTER_UNLOCK(vmMachMutexPtr);
  2370. }
  2371.  
  2372.  
  2373. /*
  2374.  * ----------------------------------------------------------------------------
  2375.  *
  2376.  * VmMach_PageValidate --
  2377.  *
  2378.  *      Validate a page for the given virtual address.  It is assumed that when
  2379.  *      this routine is called that the user context register contains the
  2380.  *    context in which the page will be validated.
  2381.  *
  2382.  * Results:
  2383.  *      None.
  2384.  *
  2385.  * Side effects:
  2386.  *      The page table and hardware segment tables associated with the segment
  2387.  *      are modified to validate the page.
  2388.  *
  2389.  * ----------------------------------------------------------------------------
  2390.  */
  2391. void
  2392. VmMach_PageValidate(virtAddrPtr, pte) 
  2393.     register    Vm_VirtAddr    *virtAddrPtr;
  2394.     Vm_PTE            pte;
  2395. {
  2396.     register  Vm_Segment    *segPtr;
  2397.     register  unsigned  char    *segTablePtr;
  2398.     register  PMEG        *pmegPtr;
  2399.     register  int        hardSeg;
  2400.     register  int        newPMEG;
  2401.     register  VmMachPTE        hardPTE;
  2402.     register  VmMachPTE        tHardPTE;
  2403.     Address            addr;
  2404.     int                i;
  2405.  
  2406.     MASTER_LOCK(vmMachMutexPtr);
  2407.  
  2408.     segPtr = virtAddrPtr->segPtr;
  2409.     addr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  2410.  
  2411.     /*
  2412.      * Find out the hardware segment that has to be mapped.
  2413.      */
  2414.     hardSeg = PageToOffSeg(virtAddrPtr->page,virtAddrPtr);
  2415.     segTablePtr = GetHardSegPtr(segPtr->machPtr, hardSeg);
  2416.  
  2417.     if (*segTablePtr == VMMACH_INV_PMEG) {
  2418.     /*
  2419.      * If there is not already a pmeg for this hardware segment, then get
  2420.      * one and initialize it.  If this is for the kernel then make
  2421.      * sure that the pmeg cannot be taken away from the kernel.
  2422.      */
  2423.     if (segPtr == vm_SysSegPtr) {
  2424.         newPMEG = PMEGGet(segPtr, hardSeg, PMEG_DONT_ALLOC);
  2425.     } else {
  2426.         newPMEG = PMEGGet(segPtr, hardSeg, 0);
  2427.     }
  2428.         *segTablePtr = newPMEG;
  2429.     } else {
  2430.     pmegPtr = &pmegArray[*segTablePtr];
  2431.     if (pmegPtr->pageCount == 0) {
  2432.         /*
  2433.          * We are using a PMEG that had a pagecount of 0.  In this case
  2434.          * it was put onto the end of the free pmeg list in anticipation
  2435.          * of someone stealing this empty pmeg.  Now we have to move
  2436.          * it off of the free list.
  2437.          */
  2438.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  2439.         List_Remove((List_Links *)pmegPtr);
  2440.         } else {
  2441.         List_Move((List_Links *)pmegPtr, LIST_ATREAR(pmegInuseList));
  2442.         }
  2443.     }
  2444.     }
  2445.     hardPTE = VMMACH_RESIDENT_BIT | VirtToPhysPage(Vm_GetPageFrame(pte));
  2446.     if (segPtr == vm_SysSegPtr) {
  2447.     int    oldContext;
  2448.     /*
  2449.      * Have to propagate the PMEG to all contexts.
  2450.      */
  2451.     oldContext = VmMachGetContextReg();
  2452.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2453.         VmMachSetContextReg(i);
  2454.         VmMachSetSegMap(addr, *segTablePtr);
  2455.     }
  2456.     VmMachSetContextReg(oldContext);
  2457.     hardPTE |= VMMACH_KRW_PROT;
  2458.     } else {
  2459.     Proc_ControlBlock    *procPtr;
  2460.         VmProcLink              *procLinkPtr;
  2461.         VmMach_Context          *contextPtr;
  2462.  
  2463.     procPtr = Proc_GetCurrentProc();
  2464.     if (virtAddrPtr->flags & USING_MAPPED_SEG) {
  2465.         addr = (Address) (VMMACH_MAP_SEG_ADDR + 
  2466.                 ((unsigned int)addr & (VMMACH_SEG_SIZE - 1)));
  2467.             /* PUT IT IN SOFTWARE OF MAP AREA FOR PROCESS */
  2468.             procPtr->vmPtr->machPtr->contextPtr->map[MAP_SEG_NUM] =
  2469.                     *segTablePtr;
  2470.         } else{
  2471.             /* update it for regular seg num */
  2472.             procPtr->vmPtr->machPtr->contextPtr->map[hardSeg] = *segTablePtr;
  2473.         }
  2474.     VmMachSetSegMap(addr, *segTablePtr);
  2475.         if (segPtr != (Vm_Segment *) NIL) {
  2476.             LIST_FORALL(segPtr->procList, (List_Links *)procLinkPtr) {
  2477.                 if (procLinkPtr->procPtr->vmPtr != (Vm_ProcInfo *) NIL &&
  2478.                         procLinkPtr->procPtr->vmPtr->machPtr !=
  2479.                         (VmMach_ProcData *) NIL &&
  2480.                         (contextPtr =
  2481.                         procLinkPtr->procPtr->vmPtr->machPtr->contextPtr) !=
  2482.                         (VmMach_Context *) NIL) {
  2483.                     contextPtr->map[hardSeg] = *segTablePtr;
  2484.                 }
  2485.             }
  2486.         }
  2487.  
  2488.  
  2489.     if ((pte & (VM_COW_BIT | VM_READ_ONLY_PROT)) ||
  2490.         (virtAddrPtr->flags & VM_READONLY_SEG)) {
  2491.         hardPTE |= VMMACH_UR_PROT;
  2492.     } else {
  2493.         hardPTE |= VMMACH_URW_PROT;
  2494.     }
  2495.     }
  2496.     tHardPTE = VmMachGetPageMap(addr);
  2497.     if (tHardPTE & VMMACH_RESIDENT_BIT) {
  2498.     hardPTE |= tHardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  2499.     for (i = 1; i < VMMACH_CLUSTER_SIZE; i++ ) {
  2500.         hardPTE |= VmMachGetPageMap(addr + i * VMMACH_PAGE_SIZE_INT) & 
  2501.                 (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  2502.     }
  2503.     } else {
  2504.     pmegArray[*segTablePtr].pageCount++;
  2505.     }
  2506.     SET_ALL_PAGE_MAP(addr, hardPTE);
  2507.     MASTER_UNLOCK(vmMachMutexPtr);
  2508. }
  2509.  
  2510.  
  2511. /*
  2512.  * ----------------------------------------------------------------------------
  2513.  *
  2514.  * PageInvalidate --
  2515.  *
  2516.  *      Invalidate a page for the given segment.  
  2517.  *
  2518.  * Results:
  2519.  *      None.
  2520.  *
  2521.  * Side effects:
  2522.  *      The page table and hardware segment tables associated with the segment
  2523.  *      are modified to invalidate the page.
  2524.  *
  2525.  * ----------------------------------------------------------------------------
  2526.  */
  2527. static void
  2528. PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  2529.     register    Vm_VirtAddr    *virtAddrPtr;
  2530.     unsigned     int        virtPage;
  2531.     Boolean            segDeletion;
  2532. {
  2533.     register VmMach_SegData    *machPtr;
  2534.     register PMEG        *pmegPtr;
  2535.     VmMachPTE            hardPTE;
  2536.     int                pmegNum;
  2537.     Address            addr;
  2538.     int                i;
  2539.  
  2540.     refModMap[virtPage] = 0;
  2541.     if (segDeletion) {
  2542.     return;
  2543.     }
  2544.     machPtr = virtAddrPtr->segPtr->machPtr;
  2545.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2546.         virtAddrPtr));
  2547.     if (pmegNum == VMMACH_INV_PMEG) {
  2548.     return;
  2549.     }
  2550.     addr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) &
  2551.                 VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2552.     hardPTE = VmMachReadPTE(pmegNum, addr);
  2553.     /*
  2554.      * Invalidate the page table entry.
  2555.      */
  2556.     for (i = 0; i < VMMACH_CLUSTER_SIZE; i++, addr += VMMACH_PAGE_SIZE_INT) {
  2557.     VmMachWritePTE(pmegNum, addr, (VmMachPTE)0);
  2558.     }
  2559.     pmegPtr = &pmegArray[pmegNum];
  2560.     if (hardPTE & VMMACH_RESIDENT_BIT) {
  2561.     pmegPtr->pageCount--;
  2562.     if (pmegPtr->pageCount == 0) {
  2563.         /*
  2564.          * When the pageCount goes to zero, the pmeg is put onto the end
  2565.          * of the free list so that it can get freed if someone else
  2566.          * needs a pmeg.  It isn't freed here because there is a fair
  2567.          * amount of overhead when freeing a pmeg so its best to keep
  2568.          * it around in case it is needed again.
  2569.          */
  2570.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  2571.         List_Insert((List_Links *)pmegPtr, 
  2572.                 LIST_ATREAR(pmegFreeList));
  2573.         } else {
  2574.         List_Move((List_Links *)pmegPtr, 
  2575.               LIST_ATREAR(pmegFreeList));
  2576.         }
  2577.     }
  2578.     }
  2579. }
  2580.  
  2581.  
  2582.  
  2583. /*
  2584.  * ----------------------------------------------------------------------------
  2585.  *
  2586.  * VmMach_PageInvalidate --
  2587.  *
  2588.  *      Invalidate a page for the given segment.  
  2589.  *
  2590.  * Results:
  2591.  *      None.
  2592.  *
  2593.  * Side effects:
  2594.  *      The page table and hardware segment tables associated with the segment
  2595.  *      are modified to invalidate the page.
  2596.  *
  2597.  * ----------------------------------------------------------------------------
  2598.  */
  2599. void
  2600. VmMach_PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  2601.     register    Vm_VirtAddr    *virtAddrPtr;
  2602.     unsigned     int        virtPage;
  2603.     Boolean            segDeletion;
  2604. {
  2605.     MASTER_LOCK(vmMachMutexPtr);
  2606.  
  2607.     PageInvalidate(virtAddrPtr, virtPage, segDeletion);
  2608.  
  2609.     MASTER_UNLOCK(vmMachMutexPtr);
  2610. }
  2611.  
  2612.  
  2613. /*
  2614.  *----------------------------------------------------------------------
  2615.  *
  2616.  * VmMach_PinUserPages --
  2617.  *
  2618.  *    Force a user page to be resident in memory.
  2619.  *
  2620.  * Results:
  2621.  *    None.
  2622.  *
  2623.  * Side effects:
  2624.  *    None.
  2625.  *
  2626.  *----------------------------------------------------------------------
  2627.  */
  2628. /*ARGSUSED*/
  2629. void
  2630. VmMach_PinUserPages(mapType, virtAddrPtr, lastPage)
  2631.     int        mapType;
  2632.     Vm_VirtAddr    *virtAddrPtr;
  2633.     int        lastPage;
  2634. {
  2635.     int                *intPtr;
  2636.     int                dummy;
  2637.     register VmMach_SegData    *machPtr;
  2638.     register int        firstSeg;
  2639.     register int        lastSeg;
  2640.  
  2641.     machPtr = virtAddrPtr->segPtr->machPtr;
  2642.  
  2643.     firstSeg = PageToOffSeg(virtAddrPtr->page,virtAddrPtr);
  2644.     lastSeg = PageToOffSeg(lastPage,virtAddrPtr);
  2645.     /*
  2646.      * Lock down the PMEG behind the first segment.
  2647.      */
  2648.     intPtr = (int *) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  2649.     while (!PMEGLock(machPtr, firstSeg)) {
  2650.     /*
  2651.      * Touch the page to bring it into memory.  We know that we can
  2652.      * safely touch it because we wouldn't have been called if these
  2653.      * weren't good addresses.
  2654.      */
  2655.     dummy = *intPtr;
  2656.     }
  2657.     /*
  2658.      * Lock down the rest of the segments.
  2659.      */
  2660.     for (firstSeg++; firstSeg <= lastSeg; firstSeg++) {
  2661.     intPtr = (int *)(firstSeg << VMMACH_SEG_SHIFT);
  2662.     while (!PMEGLock(machPtr, firstSeg)) {
  2663.         dummy = *intPtr;
  2664.     }
  2665.     }
  2666. #ifdef lint
  2667.     dummy = dummy;
  2668. #endif
  2669. }
  2670.  
  2671.  
  2672. /*
  2673.  *----------------------------------------------------------------------
  2674.  *
  2675.  * VmMach_UnpinUserPages --
  2676.  *
  2677.  *    Allow a page that was pinned to be unpinned.
  2678.  *
  2679.  * Results:
  2680.  *    None.
  2681.  *
  2682.  * Side effects:
  2683.  *    None.
  2684.  *
  2685.  *----------------------------------------------------------------------
  2686.  */
  2687. void
  2688. VmMach_UnpinUserPages(virtAddrPtr, lastPage)
  2689.     Vm_VirtAddr    *virtAddrPtr;
  2690.     int        lastPage;
  2691. {
  2692.     register int    firstSeg;
  2693.     register int    lastSeg;
  2694.     int            pmegNum;
  2695.     register VmMach_SegData    *machPtr;
  2696.  
  2697.     MASTER_LOCK(vmMachMutexPtr);
  2698.  
  2699.     machPtr = virtAddrPtr->segPtr->machPtr;
  2700.     firstSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  2701.     lastSeg = PageToOffSeg(lastPage, virtAddrPtr);
  2702.     for (; firstSeg <= lastSeg; firstSeg++) {
  2703.     pmegNum = *GetHardSegPtr(machPtr, firstSeg);
  2704.     if (pmegNum == VMMACH_INV_PMEG) {
  2705.         MASTER_UNLOCK(vmMachMutexPtr);
  2706.         panic("Pinned PMEG invalid???\n");
  2707.         return;
  2708.     }
  2709.     pmegArray[pmegNum].lockCount--;
  2710.     }
  2711.  
  2712.     MASTER_UNLOCK(vmMachMutexPtr);
  2713. }
  2714.  
  2715.  
  2716. /*
  2717.  ----------------------------------------------------------------------
  2718.  *
  2719.  * VmMach_MapInDevice --
  2720.  *
  2721.  *    Map a device at some physical address into kernel virtual address.
  2722.  *    This is for use by the controller initialization routines.
  2723.  *    This routine looks for a free page in the special range of
  2724.  *    kernel virtual that is reserved for this kind of thing and
  2725.  *    sets up the page table so that it references the device.
  2726.  *
  2727.  * Results:
  2728.  *    The kernel virtual address needed to reference the device is returned.
  2729.  *
  2730.  * Side effects:
  2731.  *    The hardware page table is modified.  This may steal another
  2732.  *    page from kernel virtual space, unless a page can be cleverly re-used.
  2733.  *
  2734.  *----------------------------------------------------------------------
  2735.  */
  2736. Address
  2737. VmMach_MapInDevice(devPhysAddr, type)
  2738.     Address    devPhysAddr;    /* Physical address of the device to map in */
  2739.     int        type;        /* Value for the page table entry type field.
  2740.                  * This depends on the address space that
  2741.                  * the devices live in, ie. VME D16 or D32 */
  2742. {
  2743.     Address         virtAddr;
  2744.     Address        freeVirtAddr = (Address)0;
  2745.     Address        freePMEGAddr = (Address)0;
  2746.     int            page;
  2747.     int            pageFrame;
  2748.     VmMachPTE        pte;
  2749.  
  2750.     /*
  2751.      * Get the page frame for the physical device so we can
  2752.      * compare it against existing pte's.
  2753.      */
  2754.     pageFrame = (unsigned)devPhysAddr >> VMMACH_PAGE_SHIFT_INT;
  2755.  
  2756.     /*
  2757.      * Spin through the segments and their pages looking for a free
  2758.      * page or a virtual page that is already mapped to the physical page.
  2759.      */
  2760.     for (virtAddr = (Address)VMMACH_DEV_START_ADDR;
  2761.          virtAddr < (Address)VMMACH_DEV_END_ADDR; ) {
  2762.     if (VmMachGetSegMap(virtAddr) == VMMACH_INV_PMEG) {
  2763.         /* 
  2764.          * If we can't find any free mappings we can use this PMEG.
  2765.          */
  2766.         if (freePMEGAddr == 0) {
  2767.         freePMEGAddr = virtAddr;
  2768.         }
  2769.         virtAddr += VMMACH_SEG_SIZE;
  2770.         continue;
  2771.     }
  2772.     /*
  2773.      * Careful, use the correct page size when incrementing virtAddr.
  2774.      * Use the real hardware size (ignore software klustering) because
  2775.      * we are at a low level munging page table entries ourselves here.
  2776.      */
  2777.     for (page = 0;
  2778.          page < VMMACH_NUM_PAGES_PER_SEG_INT;
  2779.          page++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2780.         pte = VmMachGetPageMap(virtAddr);
  2781.         if (!(pte & VMMACH_RESIDENT_BIT)) {
  2782.             if (freeVirtAddr == 0) {
  2783.             /*
  2784.              * Note the unused page in this special area of the
  2785.              * kernel virtual address space.
  2786.              */
  2787.             freeVirtAddr = virtAddr;
  2788.         }
  2789.         } else if ((pte & VMMACH_PAGE_FRAME_FIELD) == pageFrame &&
  2790.                VmMachGetPageType(pte) == type) {
  2791.         /*
  2792.          * A page is already mapped for this physical address.
  2793.          */
  2794.         return(virtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  2795.         }
  2796.     }
  2797.     }
  2798.  
  2799.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | pageFrame;
  2800. #ifdef sun3
  2801.     pte |= VMMACH_DONT_CACHE_BIT;
  2802. #endif
  2803.     VmMachSetPageType(pte, type);
  2804.     if (freeVirtAddr != 0) {
  2805.     VmMachSetPageMap(freeVirtAddr, pte);
  2806.     /*
  2807.      * Return the kernel virtual address used to access it.
  2808.      */
  2809.     return(freeVirtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  2810.     } else if (freePMEGAddr != 0) {
  2811.     int oldContext;
  2812.     int pmeg;
  2813.     int i;
  2814.  
  2815.     /*
  2816.      * Map in a new PMEG so we can use it for mapping.
  2817.      */
  2818.     pmeg = PMEGGet(vm_SysSegPtr, 
  2819.                (int) ((unsigned)freePMEGAddr >> VMMACH_SEG_SHIFT),
  2820.                PMEG_DONT_ALLOC);
  2821.     oldContext = VmMachGetContextReg();
  2822.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2823.         VmMachSetContextReg(i);
  2824.         VmMachSetSegMap(freePMEGAddr, (unsigned char) pmeg);
  2825.     }
  2826.     VmMachSetContextReg(oldContext);
  2827.     VmMachSetPageMap(freePMEGAddr, pte);
  2828.     return(freePMEGAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  2829.     } else {
  2830.     return((Address)NIL);
  2831.     }
  2832. }
  2833.  
  2834. /*----------------------------------------------------------------------
  2835.  *
  2836.  * DevBufferInit --
  2837.  *
  2838.  *    Initialize a range of virtual memory to allocate from out of the
  2839.  *    device memory space.
  2840.  *
  2841.  * Results:
  2842.  *    None.
  2843.  *
  2844.  * Side effects:
  2845.  *    The buffer struct is initialized and the hardware page map is zeroed
  2846.  *    out in the range of addresses.
  2847.  *
  2848.  *----------------------------------------------------------------------
  2849.  */
  2850. static void
  2851. DevBufferInit()
  2852. {
  2853.     Address        virtAddr;
  2854.     unsigned char    pmeg;
  2855.     int            oldContext;
  2856.     int            i;
  2857.     Address        baseAddr, endAddr;
  2858.  
  2859.     MASTER_LOCK(vmMachMutexPtr);
  2860.  
  2861.     /*
  2862.      * Round base up to next page boundary and end down to page boundary.
  2863.      */
  2864.     baseAddr = (Address)VMMACH_DMA_START_ADDR;
  2865.     endAddr = (Address)(VMMACH_DMA_START_ADDR + VMMACH_DMA_SIZE);
  2866.  
  2867.     /* 
  2868.      * Set up the hardware pages tables in the range of addresses given.
  2869.      */
  2870.     for (virtAddr = baseAddr; virtAddr < endAddr; ) {
  2871.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  2872.         panic("DevBufferInit: DMA space already valid\n");
  2873.     }
  2874.     /* 
  2875.      * Need to allocate a PMEG.
  2876.      */
  2877.     pmeg = PMEGGet(vm_SysSegPtr, 
  2878.                (int) ((unsigned)virtAddr >> VMMACH_SEG_SHIFT),
  2879.                PMEG_DONT_ALLOC);
  2880.     oldContext = VmMachGetContextReg();
  2881.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2882.         VmMachSetContextReg(i);
  2883.         VmMachSetSegMap(virtAddr, pmeg);
  2884.     }
  2885.     VmMachSetContextReg(oldContext);
  2886.     virtAddr += VMMACH_SEG_SIZE;
  2887.     }
  2888.  
  2889.     MASTER_UNLOCK(vmMachMutexPtr);
  2890. }
  2891.  
  2892. /*
  2893.  * 32Bit DMA stubs for the sun3.  The 32-bit user dvma stuff isn't on the
  2894.  * sun3's, just the sun4's.
  2895.  */
  2896. /*ARGSUSED*/
  2897. Address
  2898. VmMach_32BitDMAAlloc(numBytes, srcAddr)
  2899.     int        numBytes;        /* Number of bytes to map in. */
  2900.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  2901. {
  2902.     panic("VmMach_32BitDMAAlloc: should never be called on a sun3!\n");
  2903.     return (Address) 0;
  2904. }
  2905. /*ARGSUSED*/
  2906. void
  2907. VmMach_32BitDMAFree(numBytes, mapAddr)
  2908.     int        numBytes;        /* Number of bytes to map in. */
  2909.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  2910. {
  2911.     panic("VmMach_32BitDMAFree: should never be called on a sun3!\n");
  2912. }
  2913.  
  2914. static    Boolean    dmaPageBitMap[VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT];
  2915.  
  2916. static Boolean dmaInitialized = FALSE;
  2917.  
  2918. /*
  2919.  ----------------------------------------------------------------------
  2920.  *
  2921.  * VmMach_DMAAlloc --
  2922.  *
  2923.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  2924.  *    
  2925.  * Results:
  2926.  *    Pointer into kernel virtual address space of where to access the
  2927.  *    memory, or NIL if the request couldn't be satisfied.
  2928.  *
  2929.  * Side effects:
  2930.  *    The hardware page table is modified.
  2931.  *
  2932.  *----------------------------------------------------------------------
  2933.  */
  2934. Address
  2935. VmMach_DMAAlloc(numBytes, srcAddr)
  2936.     int        numBytes;        /* Number of bytes to map in. */
  2937.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  2938. {
  2939.     Address    beginAddr;
  2940.     Address    endAddr;
  2941.     int        numPages;
  2942.     int        i, j;
  2943.     VmMachPTE    pte;
  2944.     Boolean    foundIt = FALSE;
  2945.     int        virtPage;
  2946.  
  2947.     if (!dmaInitialized) {
  2948.     dmaInitialized = TRUE;
  2949.     DevBufferInit();
  2950.     }
  2951.     /* calculate number of pages needed */
  2952.                         /* beginning of first page */
  2953.     beginAddr = (Address) (((unsigned int)(srcAddr)) & ~VMMACH_OFFSET_MASK_INT);
  2954.                         /* begging of last page */
  2955.     endAddr = (Address) ((((unsigned int) srcAddr) + numBytes) &
  2956.         ~VMMACH_OFFSET_MASK_INT);
  2957.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  2958.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  2959.  
  2960.     /* see if request can be satisfied */
  2961.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  2962.     if (dmaPageBitMap[i] == 1) {
  2963.         continue;
  2964.     }
  2965.     for (j = 1; j < numPages; j++) {
  2966.         if (dmaPageBitMap[i + j] == 1) {
  2967.         break;
  2968.         }
  2969.     }
  2970.     if (j == numPages) {
  2971.         foundIt = TRUE;
  2972.         break;
  2973.     }
  2974.     }
  2975.     if (!foundIt) {
  2976.     return (Address) NIL;
  2977.     }
  2978.     for (j = 0; j < numPages; j++) {
  2979.     dmaPageBitMap[i + j] = 1;    /* allocate page */
  2980.     virtPage = ((unsigned int) srcAddr) >> VMMACH_PAGE_SHIFT;
  2981.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  2982.           VirtToPhysPage(Vm_GetKernPageFrame(virtPage));
  2983.     SET_ALL_PAGE_MAP(((i + j) * VMMACH_PAGE_SIZE_INT) +
  2984.         VMMACH_DMA_START_ADDR, pte);
  2985.     srcAddr += VMMACH_PAGE_SIZE;
  2986.     }
  2987.     beginAddr = (Address) (VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT) +
  2988.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  2989.     return beginAddr;
  2990. }
  2991.  
  2992. /*
  2993.  ----------------------------------------------------------------------
  2994.  *
  2995.  * VmMach_DMAAllocContiguous --
  2996.  *
  2997.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  2998.  *    
  2999.  * Results:
  3000.  *    Pointer into kernel virtual address space of where to access the
  3001.  *    memory, or NIL if the request couldn't be satisfied.
  3002.  *
  3003.  * Side effects:
  3004.  *    The hardware page table is modified.
  3005.  *
  3006.  *----------------------------------------------------------------------
  3007.  */
  3008. ReturnStatus
  3009. VmMach_DMAAllocContiguous(inScatGathPtr, scatGathLength, outScatGathPtr)
  3010.     register Net_ScatterGather    *inScatGathPtr;
  3011.     register int        scatGathLength;
  3012.     register Net_ScatterGather    *outScatGathPtr;
  3013. {
  3014.     Address    beginAddr;
  3015.     Address    endAddr;
  3016.     int        numPages;
  3017.     int        i, j;
  3018.     VmMachPTE    pte;
  3019.     Boolean    foundIt = FALSE;
  3020.     int        virtPage;
  3021.     Net_ScatterGather        *inPtr;
  3022.     Net_ScatterGather        *outPtr;
  3023.     int                pageOffset;
  3024.     Address            srcAddr;
  3025.  
  3026.     if (!dmaInitialized) {
  3027.     dmaInitialized = TRUE;
  3028.     DevBufferInit();
  3029.     }
  3030.     /* calculate number of pages needed */
  3031.     inPtr = inScatGathPtr;
  3032.     outPtr = outScatGathPtr;
  3033.     numPages = 0;
  3034.     for (i = 0; i < scatGathLength; i++) {
  3035.     if (inPtr->length > 0) {
  3036.         /* beginning of first page */
  3037.         beginAddr = (Address) (((unsigned int)(inPtr->bufAddr)) & 
  3038.             ~VMMACH_OFFSET_MASK_INT);
  3039.         /* beginning of last page */
  3040.         endAddr = (Address) ((((unsigned int) inPtr->bufAddr) + 
  3041.         inPtr->length - 1) & ~VMMACH_OFFSET_MASK_INT);
  3042.         /* 
  3043.          * Temporarily store the number of pages in the out scatter/gather
  3044.          * array.
  3045.          */
  3046.         outPtr->length =
  3047.             (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3048.             (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  3049.     } else {
  3050.         outPtr->length = 0;
  3051.     }
  3052.     if ((i == 0) && (outPtr->length != 1)) {
  3053.         panic("Help! Help! I'm being repressed!\n");
  3054.     }
  3055.     numPages += outPtr->length;
  3056.     inPtr++;
  3057.     outPtr++;
  3058.     }
  3059.  
  3060.     /* see if request can be satisfied */
  3061.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  3062.     if (dmaPageBitMap[i] == 1) {
  3063.         continue;
  3064.     }
  3065.     for (j = 1; j < numPages; j++) {
  3066.         if (dmaPageBitMap[i + j] == 1) {
  3067.         break;
  3068.         }
  3069.     }
  3070.     if (j == numPages) {
  3071.         foundIt = TRUE;
  3072.         break;
  3073.     }
  3074.     }
  3075.     if (!foundIt) {
  3076.     return FAILURE;
  3077.     }
  3078.     pageOffset = i;
  3079.     inPtr = inScatGathPtr;
  3080.     outPtr = outScatGathPtr;
  3081.     for (i = 0; i < scatGathLength; i++) {
  3082.     srcAddr = inPtr->bufAddr;
  3083.     numPages = outPtr->length;
  3084.     for (j = 0; j < numPages; j++) {
  3085.         dmaPageBitMap[pageOffset + j] = 1;    /* allocate page */
  3086.         virtPage = ((unsigned int) srcAddr) >> VMMACH_PAGE_SHIFT;
  3087.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  3088.           VirtToPhysPage(Vm_GetKernPageFrame(virtPage));
  3089.         SET_ALL_PAGE_MAP(((pageOffset + j) * VMMACH_PAGE_SIZE_INT) +
  3090.             VMMACH_DMA_START_ADDR, pte);
  3091.         srcAddr += VMMACH_PAGE_SIZE;
  3092.     }
  3093.     outPtr->bufAddr = (Address) (VMMACH_DMA_START_ADDR + 
  3094.         (pageOffset * VMMACH_PAGE_SIZE_INT) + 
  3095.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  3096.     pageOffset += numPages;
  3097.     outPtr->length = inPtr->length;
  3098.     inPtr++;
  3099.     outPtr++;
  3100.     }
  3101.     return SUCCESS;
  3102. }
  3103.  
  3104.  
  3105. /*
  3106.  ----------------------------------------------------------------------
  3107.  *
  3108.  * VmMach_DMAFree --
  3109.  *
  3110.  *    Free a previously allocated set of virtual pages for a routine that
  3111.  *    used them for mapping purposes.
  3112.  *    
  3113.  * Results:
  3114.  *    None.
  3115.  *
  3116.  * Side effects:
  3117.  *    The hardware page table is modified.
  3118.  *
  3119.  *----------------------------------------------------------------------
  3120.  */
  3121. void
  3122. VmMach_DMAFree(numBytes, mapAddr)
  3123.     int        numBytes;        /* Number of bytes to map in. */
  3124.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  3125. {
  3126.     Address    beginAddr;
  3127.     Address    endAddr;
  3128.     int        numPages;
  3129.     int        i, j;
  3130.  
  3131.     /* calculate number of pages to free */
  3132.                         /* beginning of first page */
  3133.     beginAddr = (Address) (((unsigned int) mapAddr) & ~VMMACH_OFFSET_MASK_INT);
  3134.                         /* beginning of last page */
  3135.     endAddr = (Address) ((((unsigned int) mapAddr) + numBytes) &
  3136.         ~VMMACH_OFFSET_MASK_INT);
  3137.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3138.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  3139.  
  3140.     i = (((unsigned int) mapAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3141.     (VMMACH_DMA_START_ADDR >> VMMACH_PAGE_SHIFT_INT);
  3142.     for (j = 0; j < numPages; j++) {
  3143.     dmaPageBitMap[i + j] = 0;    /* free page */
  3144.     SET_ALL_PAGE_MAP(mapAddr, (VmMachPTE) 0);
  3145.     mapAddr = (Address)(((unsigned int) mapAddr) + VMMACH_PAGE_SIZE_INT);
  3146.     }
  3147.     return;
  3148. }
  3149.  
  3150.  
  3151. #if 0 /* Dead code shirriff 9/90 */
  3152. /*
  3153.  * ----------------------------------------------------------------------------
  3154.  *
  3155.  * VmMach_GetDevicePage --
  3156.  *
  3157.  *      Allocate and validate a page at the given virtual address.  It is
  3158.  *    assumed that this page does not fall into the range of virtual 
  3159.  *    addresses used to allocate kernel code and data and that there is
  3160.  *    already a PMEG allocate for it.
  3161.  *
  3162.  * Results:
  3163.  *      None.
  3164.  *
  3165.  * Side effects:
  3166.  *      The hardware segment table for the kernel is modified to validate the
  3167.  *    the page.
  3168.  *
  3169.  * ----------------------------------------------------------------------------
  3170.  */
  3171. void
  3172. VmMach_GetDevicePage(virtAddr) 
  3173.     Address    virtAddr; /* Virtual address where a page has to be 
  3174.                * validated at. */
  3175. {
  3176.     VmMachPTE    pte;
  3177.     int        page;
  3178.  
  3179.     page = Vm_KernPageAllocate();
  3180.     if (page == -1) {
  3181.     panic("Vm_GetDevicePage: Couldn't get memory\n");
  3182.     }
  3183.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(page);
  3184.     SET_ALL_PAGE_MAP(virtAddr, pte);
  3185. }
  3186.  
  3187. #endif
  3188.  
  3189. /*
  3190.  * ----------------------------------------------------------------------------
  3191.  *
  3192.  * VmMach_MapKernelIntoUser --
  3193.  *
  3194.  *      Map a portion of kernel memory into the user's heap segment.  
  3195.  *    It will only map objects on hardware segment boundaries.  This is 
  3196.  *    intended to be used to map devices such as video memory.
  3197.  *
  3198.  *    NOTE: It is assumed that the user process knows what the hell it is
  3199.  *          doing.
  3200.  *
  3201.  * Results:
  3202.  *      Return the virtual address that it chose to map the memory at.
  3203.  *
  3204.  * Side effects:
  3205.  *      The hardware segment table for the user process's segment is modified
  3206.  *    to map in the addresses.
  3207.  *
  3208.  * ----------------------------------------------------------------------------
  3209.  */
  3210. ReturnStatus
  3211. VmMach_MapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr,
  3212.              realVirtAddrPtr) 
  3213.     unsigned    int    kernelVirtAddr;    /* Kernel virtual address to map in. */
  3214.     int    numBytes;            /* Number of bytes to map. */
  3215.     unsigned int userVirtAddr;    /* User virtual address to attempt to start 
  3216.                    mapping in at. */
  3217.     unsigned int *realVirtAddrPtr;/* Where we were able to start mapping at. */
  3218. {
  3219.     Address             newUserVirtAddr;
  3220.     ReturnStatus        status;
  3221.  
  3222.     status = VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes,
  3223.             userVirtAddr, &newUserVirtAddr);
  3224.  
  3225.     if (status != SUCCESS) {
  3226.         return status;
  3227.     }
  3228.  
  3229.     return Vm_CopyOut(4, (Address) &newUserVirtAddr, (Address) realVirtAddrPtr);
  3230. }
  3231.  
  3232.  
  3233. /*
  3234.  * ----------------------------------------------------------------------------
  3235.  *
  3236.  * Vm_IntMapKernelIntoUser --
  3237.  *
  3238.  *      Map a portion of kernel memory into the user's heap segment.
  3239.  *      It will only map objects on hardware segment boundaries.  This is
  3240.  *      intended to be used to map devices such as video memory.
  3241.  *
  3242.  *      This routine can be called from within the kernel since it doesn't
  3243.  *      do a Vm_CopyOut of the new user virtual address.
  3244.  *
  3245.  *      NOTE: It is assumed that the user process knows what the hell it is
  3246.  *            doing.
  3247.  *
  3248.  * Results:
  3249.  *      SUCCESS or FAILURE status.
  3250.  *      Return the virtual address that it chose to map the memory at in
  3251.  *      an out parameter.
  3252.  *
  3253.  * Side effects:
  3254.  *      The hardware segment table for the user process's segment is modified
  3255.  *      to map in the addresses.
  3256.  *
  3257.  * ----------------------------------------------------------------------------
  3258.  */
  3259. ReturnStatus
  3260. VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr, newAddrPtr)
  3261.     unsigned int        kernelVirtAddr;         /* Kernel virtual address
  3262.                                                  * to map in. */
  3263.     int numBytes;                               /* Number of bytes to map. */
  3264.     unsigned int        userVirtAddr;           /* User virtual address to
  3265.                                                  * attempt to start mapping
  3266.                                                  * in at. */
  3267.     Address             *newAddrPtr;            /* New user address. */
  3268. {
  3269.     int                numSegs;
  3270.     int                firstPage;
  3271.     int                numPages;
  3272.     Proc_ControlBlock        *procPtr;
  3273.     register    Vm_Segment    *segPtr;
  3274.     int                hardSegNum;
  3275.     int                i;
  3276.     unsigned int        pte;
  3277.  
  3278.     procPtr = Proc_GetCurrentProc();
  3279.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  3280.  
  3281.     numSegs = numBytes >> VMMACH_SEG_SHIFT;
  3282.     numPages = numSegs * VMMACH_SEG_SIZE / VMMACH_PAGE_SIZE;
  3283.  
  3284.     /*
  3285.      * Make user virtual address hardware segment aligned (round up) and 
  3286.      * make sure that there is enough space to map things.
  3287.      */
  3288.     hardSegNum = 
  3289.         (unsigned int) (userVirtAddr + VMMACH_SEG_SIZE - 1) >> VMMACH_SEG_SHIFT;
  3290.     userVirtAddr = hardSegNum << VMMACH_SEG_SHIFT;
  3291.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  3292.     return(SYS_INVALID_ARG);
  3293.     }
  3294.  
  3295.     /*
  3296.      * Make sure will fit into the kernel's VAS.  Assume that is hardware
  3297.      * segment aligned.
  3298.      */
  3299.     hardSegNum = (unsigned int) (kernelVirtAddr) >> VMMACH_SEG_SHIFT;
  3300.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  3301.     return(SYS_INVALID_ARG);
  3302.     }
  3303.  
  3304.     /*
  3305.      * Invalidate all virtual memory for the heap segment of this process
  3306.      * in the given range of virtual addresses that we are to map.  This
  3307.      * assures us that there aren't any hardware pages allocated for this
  3308.      * segment in this range of addresses.
  3309.      */
  3310.     firstPage = (unsigned int) (userVirtAddr) >> VMMACH_PAGE_SHIFT;
  3311.     (void)Vm_DeleteFromSeg(segPtr, firstPage, firstPage + numPages - 1);
  3312.  
  3313.     /*
  3314.      * Now go into the kernel's hardware segment table and copy the
  3315.      * segment table entries into the heap segments hardware segment table.
  3316.      */
  3317.     bcopy((Address)GetHardSegPtr(vm_SysSegPtr->machPtr, hardSegNum),
  3318.     (Address)GetHardSegPtr(segPtr->machPtr,
  3319.         (unsigned int)userVirtAddr >> VMMACH_SEG_SHIFT), numSegs);
  3320.     for (i = 0; i < numSegs * VMMACH_NUM_PAGES_PER_SEG_INT; i++) {
  3321.     pte = VmMachGetPageMap((Address)(kernelVirtAddr +
  3322.         (i * VMMACH_PAGE_SIZE_INT)));
  3323.     pte &= ~VMMACH_KR_PROT;
  3324.     pte |= VMMACH_URW_PROT;
  3325.     VmMachSetPageMap((Address)(kernelVirtAddr + (i*VMMACH_PAGE_SIZE_INT)),
  3326.         pte);
  3327.     }
  3328.  
  3329.     /*
  3330.      * Make sure this process never migrates.
  3331.      */
  3332.     Proc_NeverMigrate(procPtr);
  3333.     
  3334.     /* 
  3335.      * Reinitialize this process's context using the new segment table.
  3336.      */
  3337.     VmMach_ReinitContext(procPtr);
  3338.     *newAddrPtr = (Address)userVirtAddr;
  3339.  
  3340.     return SUCCESS;
  3341. }
  3342.  
  3343.  
  3344. /*
  3345.  *----------------------------------------------------------------------
  3346.  *
  3347.  * VmMach_FlushPage --
  3348.  *
  3349.  *    Flush the page at the given virtual address from all caches.  We
  3350.  *    don't have to do anything on the Sun-2 and Sun-3 workstations
  3351.  *    that we have.
  3352.  *
  3353.  * Results:
  3354.  *    None.
  3355.  *
  3356.  * Side effects:
  3357.  *    The given page is flushed from the caches.
  3358.  *
  3359.  *----------------------------------------------------------------------
  3360.  */
  3361. /*ARGSUSED*/
  3362. void
  3363. VmMach_FlushPage(virtAddrPtr, invalidate)
  3364.     Vm_VirtAddr    *virtAddrPtr;
  3365.     Boolean    invalidate;    /* Should invalidate the pte after flushing. */
  3366. {
  3367. }
  3368.  
  3369.  
  3370. /*
  3371.  *----------------------------------------------------------------------
  3372.  *
  3373.  * VmMach_HandleSegMigration --
  3374.  *
  3375.  *    Handle machine-dependent aspects of segment preparation for
  3376.  *    migration.  There's nothing to do on this machine.
  3377.  *
  3378.  * Results:
  3379.  *    None.
  3380.  *
  3381.  * Side effects:
  3382.  *    None.
  3383.  *
  3384.  *----------------------------------------------------------------------
  3385.  */
  3386. /*ARGSUSED*/
  3387. void
  3388. VmMach_HandleSegMigration(segPtr)
  3389.     Vm_Segment    *segPtr;
  3390. {
  3391.     return;
  3392. }
  3393.  
  3394.  
  3395. /*
  3396.  *----------------------------------------------------------------------
  3397.  *
  3398.  * VmMach_SetProtForDbg --
  3399.  *
  3400.  *    Set the protection of the kernel pages for the debugger.
  3401.  *
  3402.  * Results:
  3403.  *    None.
  3404.  *
  3405.  * Side effects:
  3406.  *    The protection is set for the given range of kernel addresses.
  3407.  *
  3408.  *----------------------------------------------------------------------
  3409.  */
  3410. void
  3411. VmMach_SetProtForDbg(readWrite, numBytes, addr)
  3412.     Boolean    readWrite;    /* TRUE if should make pages writable, FALSE
  3413.                  * if should make read-only. */
  3414.     int        numBytes;    /* Number of bytes to change protection for. */
  3415.     Address    addr;        /* Address to start changing protection at. */
  3416. {
  3417.     register    Address        virtAddr;
  3418.     register    VmMachPTE     pte;
  3419.     register    int        firstPage;
  3420.     register    int        lastPage;
  3421.  
  3422.     firstPage = (unsigned)addr >> VMMACH_PAGE_SHIFT;
  3423.     lastPage = ((unsigned)addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  3424.     for (; firstPage <= lastPage; firstPage++) {
  3425.     virtAddr = (Address) (firstPage << VMMACH_PAGE_SHIFT);
  3426.     pte = VmMachGetPageMap(virtAddr);
  3427.     pte &= ~VMMACH_PROTECTION_FIELD;
  3428.     pte |= readWrite ? VMMACH_KRW_PROT : VMMACH_KR_PROT;
  3429.     SET_ALL_PAGE_MAP(virtAddr, pte);
  3430.     }
  3431. }
  3432.  
  3433.  
  3434. /*
  3435.  *----------------------------------------------------------------------
  3436.  *
  3437.  * VmMach_Cmd --
  3438.  *
  3439.  *    Machine dependent vm commands.
  3440.  *
  3441.  * Results:
  3442.  *    None.
  3443.  *
  3444.  * Side effects:
  3445.  *    None.
  3446.  *
  3447.  *----------------------------------------------------------------------
  3448.  */
  3449. /*ARGSUSED*/
  3450. ReturnStatus
  3451. VmMach_Cmd(command, arg)
  3452.     int    command;
  3453.     int arg;
  3454. {
  3455.     return(GEN_INVALID_ARG);
  3456. }
  3457.  
  3458.  
  3459. /*
  3460.  *----------------------------------------------------------------------
  3461.  *
  3462.  * VmMach_FlushCode --
  3463.  *
  3464.  *    Machine dependent vm commands.
  3465.  *
  3466.  * Results:
  3467.  *    None.
  3468.  *
  3469.  * Side effects:
  3470.  *    None.
  3471.  *
  3472.  *----------------------------------------------------------------------
  3473.  */
  3474. /*ARGSUSED*/
  3475. void
  3476. VmMach_FlushCode(procPtr, virtAddrPtr, virtPage, numBytes)
  3477.     Proc_ControlBlock    *procPtr;
  3478.     Vm_VirtAddr        *virtAddrPtr;
  3479.     unsigned        virtPage;
  3480.     int            numBytes;
  3481. {
  3482. }
  3483.  
  3484. /*
  3485.  * Dummy function which will turn out to be the function that the debugger
  3486.  * prints out on a backtrace after a trap.  The debugger gets confused
  3487.  * because trap stacks originate from assembly language stacks.  I decided
  3488.  * to make a dummy procedure because it was to confusing seeing the
  3489.  * previous procedure (VmMach_MapKernelIntoUser) on every backtrace.
  3490.  */
  3491. void
  3492. VmMachTrap()
  3493. {
  3494. }
  3495.  
  3496. /*
  3497.  *----------------------------------------------------------------------
  3498.  *
  3499.  * ByteFill --
  3500.  *
  3501.  *    Fill numBytes at the given address.  This routine is optimized to do 
  3502.  *      4-byte fills.  However, if the address is odd then it is forced to
  3503.  *      do single byte fills.
  3504.  *
  3505.  * Results:
  3506.  *    numBytes bytes of the fill byte are placed at *destPtr at the 
  3507.  *    given address.
  3508.  *
  3509.  * Side effects:
  3510.  *    None.
  3511.  *
  3512.  *----------------------------------------------------------------------
  3513.  */
  3514.  
  3515. static void
  3516. ByteFill(fillByte, numBytes, destPtr)
  3517.     register unsigned int fillByte;    /* The byte to be filled in. */
  3518.     register int numBytes;    /* The number of bytes to be filled in. */
  3519.     Address destPtr;        /* Where to fill. */
  3520. {
  3521.     register unsigned int fillInt = 
  3522.     (fillByte) | (fillByte << 8) | (fillByte << 16) | (fillByte << 24);
  3523.  
  3524.     register int *dPtr = (int *) destPtr;
  3525.     
  3526.     /*
  3527.      * If the address is on an aligned boundary then fill in as much
  3528.      * as we can in big transfers (and also avoid loop overhead by
  3529.      * storing many fill ints per iteration).  Once we have less than
  3530.      * 4 bytes to fill then it must be done by byte copies.
  3531.      */
  3532. #define WORDMASK    0x1
  3533.  
  3534.     if (((int) dPtr & WORDMASK) == 0) {
  3535.     while (numBytes >= 32) {
  3536.         *dPtr++ = fillInt;
  3537.         *dPtr++ = fillInt;
  3538.         *dPtr++ = fillInt;
  3539.         *dPtr++ = fillInt;
  3540.         *dPtr++ = fillInt;
  3541.         *dPtr++ = fillInt;
  3542.         *dPtr++ = fillInt;
  3543.         *dPtr++ = fillInt;
  3544.         numBytes -= 32;
  3545.     }
  3546.     while (numBytes >= 4) {
  3547.         *dPtr++ = fillInt;
  3548.         numBytes -= 4;
  3549.     }
  3550.     destPtr = (char *) dPtr;
  3551.     }
  3552.  
  3553.     /*
  3554.      * Fill in the remaining bytes
  3555.      */
  3556.  
  3557.     while (numBytes > 0) {
  3558.     *destPtr++ = fillByte;
  3559.     numBytes--;
  3560.     }
  3561. }
  3562.  
  3563.  
  3564. #define ALLOC(x,s)    (sharedData->allocVector[(x)]=s)
  3565. #define FREE(x)        (sharedData->allocVector[(x)]=0)
  3566. #define SIZE(x)        (sharedData->allocVector[(x)])
  3567. #define ISFREE(x)    (sharedData->allocVector[(x)]==0)
  3568.  
  3569.  
  3570.  
  3571. /*
  3572.  * ----------------------------------------------------------------------------
  3573.  *
  3574.  * VmMach_Alloc --
  3575.  *
  3576.  *      Allocates a region of shared memory;
  3577.  *
  3578.  * Results:
  3579.  *      SUCCESS if the region can be allocated.
  3580.  *    The starting address is returned in addr.
  3581.  *
  3582.  * Side effects:
  3583.  *      The allocation vector is updated.
  3584.  *
  3585.  * ----------------------------------------------------------------------------
  3586.  */
  3587. static ReturnStatus
  3588. VmMach_Alloc(sharedData, regionSize, addr)
  3589.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info.  */
  3590.     int            regionSize;    /* Size of region to allocate. */
  3591.     Address        *addr;        /* Address of region. */
  3592. {
  3593.     int numBlocks = (regionSize+VMMACH_SHARED_BLOCK_SIZE-1) /
  3594.         VMMACH_SHARED_BLOCK_SIZE;
  3595.     int i, blockCount, firstBlock;
  3596.  
  3597.     if (sharedData->allocVector == (int *)NULL || sharedData->allocVector ==
  3598.         (int *)NIL) {
  3599.     dprintf("VmMach_Alloc: allocVector uninitialized!\n");
  3600.     }
  3601.  
  3602.     /*
  3603.      * Loop through the alloc vector until we find numBlocks free blocks
  3604.      * consecutively.
  3605.      */
  3606.     blockCount = 0;
  3607.     for (i=sharedData->allocFirstFree;
  3608.         i<=VMMACH_SHARED_NUM_BLOCKS-1 && blockCount<numBlocks;i++) {
  3609.     if (ISFREE(i)) {
  3610.         blockCount++;
  3611.     } else {
  3612.         blockCount = 0;
  3613.         if (i==sharedData->allocFirstFree) {
  3614.         sharedData->allocFirstFree++;
  3615.         }
  3616.     }
  3617.     }
  3618.     if (blockCount < numBlocks) {
  3619.     if (debugVmStubs) {
  3620.         dprintf("VmMach_Alloc: got %d blocks of %d of %d total\n",
  3621.             blockCount,numBlocks,VMMACH_SHARED_NUM_BLOCKS);
  3622.     }
  3623.     return VM_NO_SEGMENTS;
  3624.     }
  3625.     firstBlock = i-blockCount;
  3626.     if (firstBlock == sharedData->allocFirstFree) {
  3627.     sharedData->allocFirstFree += blockCount;
  3628.     }
  3629.     *addr = (Address)(firstBlock*VMMACH_SHARED_BLOCK_SIZE +
  3630.         VMMACH_SHARED_START_ADDR);
  3631.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  3632.     ALLOC(i,numBlocks);
  3633.     }
  3634.     dprintf("VmMach_Alloc: got %d blocks at %d (%x)\n",
  3635.         numBlocks,firstBlock,*addr);
  3636.     return SUCCESS;
  3637. }
  3638.  
  3639.  
  3640. /*
  3641.  * ----------------------------------------------------------------------------
  3642.  *
  3643.  * VmMach_Unalloc --
  3644.  *
  3645.  *      Frees a region of shared address space.
  3646.  *
  3647.  * Results:
  3648.  *      None.
  3649.  *
  3650.  * Side effects:
  3651.  *      The allocation vector is updated.
  3652.  *
  3653.  * ----------------------------------------------------------------------------
  3654.  */
  3655.  
  3656. static void
  3657. VmMach_Unalloc(sharedData, addr)
  3658.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info. */
  3659.     Address    addr;        /* Address of region. */
  3660. {
  3661.     int firstBlock = ((int)addr-VMMACH_SHARED_START_ADDR) /
  3662.         VMMACH_SHARED_BLOCK_SIZE;
  3663.     int numBlocks = SIZE(firstBlock);
  3664.     int i;
  3665.  
  3666.     dprintf("VmMach_Unalloc: freeing %d blocks at %x\n",numBlocks,addr);
  3667.     if (firstBlock < sharedData->allocFirstFree) {
  3668.     sharedData->allocFirstFree = firstBlock;
  3669.     }
  3670.     for (i=0;i<numBlocks;i++) {
  3671.     if (ISFREE(i+firstBlock)) {
  3672.         if (debugVmStubs) {
  3673.         printf("Freeing free shared address %d %d %x\n",i,i+firstBlock,
  3674.             (int)addr);
  3675.         }
  3676.         return;
  3677.     }
  3678.     FREE(i+firstBlock);
  3679.     }
  3680. }
  3681.  
  3682. /*
  3683.  * ----------------------------------------------------------------------------
  3684.  *
  3685.  * VmMach_SharedStartAddr --
  3686.  *
  3687.  *      Determine the starting address for a shared segment.
  3688.  *
  3689.  * Results:
  3690.  *      Returns the proper start address for the segment.
  3691.  *
  3692.  * Side effects:
  3693.  *      Allocates part of the shared address space.
  3694.  *
  3695.  * ----------------------------------------------------------------------------
  3696.  */
  3697. ReturnStatus
  3698. VmMach_SharedStartAddr(procPtr,size,reqAddr, fixed)
  3699.     Proc_ControlBlock   *procPtr;
  3700.     int             size;           /* Length of shared segment. */
  3701.     Address         *reqAddr;        /* Requested start address. */
  3702.     int             fixed;          /* 1 if fixed address requested. */
  3703. {
  3704.     int numBlocks = (size+VMMACH_SHARED_BLOCK_SIZE-1) /
  3705.             VMMACH_SHARED_BLOCK_SIZE;
  3706.     int firstBlock = (((int)*reqAddr)-VMMACH_SHARED_START_ADDR) /
  3707.             VMMACH_SHARED_BLOCK_SIZE;
  3708.     int i;
  3709.     VmMach_SharedData   *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  3710.  
  3711.     if (fixed==0) {
  3712.         return VmMach_Alloc(sharedData, size, reqAddr);
  3713.     } else {
  3714.         for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  3715.             if (i>0) {
  3716.                 ALLOC(i,numBlocks);
  3717.             }
  3718.         }
  3719.         return SUCCESS;
  3720.     }
  3721. }
  3722.  
  3723. /*
  3724.  * ----------------------------------------------------------------------------
  3725.  *
  3726.  * VmMach_SharedProcStart --
  3727.  *
  3728.  *      Perform machine dependent initialization of shared memory
  3729.  *    for this process.
  3730.  *
  3731.  * Results:
  3732.  *      None.
  3733.  *
  3734.  * Side effects:
  3735.  *      The storage allocation structures are initialized.
  3736.  *
  3737.  * ----------------------------------------------------------------------------
  3738.  */
  3739. void
  3740. VmMach_SharedProcStart(procPtr)
  3741.     Proc_ControlBlock    *procPtr;
  3742. {
  3743.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  3744.     dprintf("VmMach_SharedProcStart: initializing proc's allocVector\n");
  3745.     if (sharedData->allocVector != (int *)NIL) {
  3746.     panic("VmMach_SharedProcStart: allocVector not NIL\n");
  3747.     }
  3748.     sharedData->allocVector =
  3749.         (int *)malloc(VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  3750.     sharedData->allocFirstFree = 0;
  3751.     bzero((Address) sharedData->allocVector, VMMACH_SHARED_NUM_BLOCKS*
  3752.         sizeof(int));
  3753. #if 0
  3754.     procPtr->vmPtr->sharedStart = (Address) VMMACH_SHARED_START_ADDR;
  3755.     procPtr->vmPtr->sharedEnd = (Address) VMMACH_SHARED_START_ADDR +
  3756.         VMMACH_USER_SHARED_PAGES*VMMACH_PAGE_SIZE;
  3757. #else
  3758.     procPtr->vmPtr->sharedStart = (Address) 0x00000000;
  3759.     procPtr->vmPtr->sharedEnd = (Address) 0xffff0000;
  3760.     
  3761. #endif
  3762. }
  3763.  
  3764. /*
  3765.  * ----------------------------------------------------------------------------
  3766.  *
  3767.  * VmMach_SharedSegFinish --
  3768.  *
  3769.  *      Perform machine dependent cleanup of shared memory
  3770.  *    for this segment.
  3771.  *
  3772.  * Results:
  3773.  *      None.
  3774.  *
  3775.  * Side effects:
  3776.  *      The storage allocation structures are freed.
  3777.  *
  3778.  * ----------------------------------------------------------------------------
  3779.  */
  3780. void
  3781. VmMach_SharedSegFinish(procPtr,addr)
  3782.     Proc_ControlBlock    *procPtr;
  3783.     Address        addr;
  3784. {
  3785.     VmMach_Unalloc(&procPtr->vmPtr->machPtr->sharedData,addr);
  3786. }
  3787.  
  3788. /*
  3789.  * ----------------------------------------------------------------------------
  3790.  *
  3791.  * VmMach_SharedProcFinish --
  3792.  *
  3793.  *      Perform machine dependent cleanup of shared memory
  3794.  *    for this process.
  3795.  *
  3796.  * Results:
  3797.  *      None.
  3798.  *
  3799.  * Side effects:
  3800.  *      The storage allocation structures are freed.
  3801.  *
  3802.  * ----------------------------------------------------------------------------
  3803.  */
  3804. void
  3805. VmMach_SharedProcFinish(procPtr)
  3806.     Proc_ControlBlock    *procPtr;
  3807. {
  3808.     dprintf("VmMach_SharedProcFinish: freeing process's allocVector\n");
  3809.     free((Address)procPtr->vmPtr->machPtr->sharedData.allocVector);
  3810.     procPtr->vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  3811. }
  3812.  
  3813. /*
  3814.  * ----------------------------------------------------------------------------
  3815.  *
  3816.  * VmMach_CopySharedMem --
  3817.  *
  3818.  *      Copies machine-dependent shared memory data structures to handle
  3819.  *      a fork.
  3820.  *
  3821.  * Results:
  3822.  *      None.
  3823.  *
  3824.  * Side effects:
  3825.  *      The new process gets a copy of the shared memory structures.
  3826.  *
  3827.  * ----------------------------------------------------------------------------
  3828.  */
  3829. void
  3830. VmMach_CopySharedMem(parentProcPtr, childProcPtr)
  3831.     Proc_ControlBlock   *parentProcPtr; /* Parent process. */
  3832.     Proc_ControlBlock   *childProcPtr;  /* Child process. */
  3833. {
  3834.     VmMach_SharedData   *childSharedData =
  3835.             &childProcPtr->vmPtr->machPtr->sharedData;
  3836.     VmMach_SharedData   *parentSharedData =
  3837.             &parentProcPtr->vmPtr->machPtr->sharedData;
  3838.  
  3839.     VmMach_SharedProcStart(childProcPtr);
  3840.  
  3841.     bcopy((Address)parentSharedData->allocVector,
  3842.         (Address)childSharedData->allocVector,
  3843.             VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  3844.     childSharedData->allocFirstFree = parentSharedData->allocFirstFree;
  3845. }
  3846.  
  3847. /*
  3848.  * ----------------------------------------------------------------------------
  3849.  *
  3850.  * VmMach_LockCachePage --
  3851.  *
  3852.  *      Perform machine dependent locking of a kernel resident file cache
  3853.  *    page.
  3854.  *
  3855.  * Results:
  3856.  *      None.
  3857.  *
  3858.  * Side effects:
  3859.  *
  3860.  * ----------------------------------------------------------------------------
  3861.  */
  3862. /*ARGSUSED*/
  3863. void
  3864. VmMach_LockCachePage(kernelAddress)
  3865.     Address    kernelAddress;    /* Address on page to lock. */
  3866. {
  3867.     /*
  3868.      * Sun3 leaves file cache pages always available so there is no need to
  3869.      * lock or unlock them.
  3870.      */
  3871.     return;
  3872. }
  3873.  
  3874. /*
  3875.  * ----------------------------------------------------------------------------
  3876.  *
  3877.  * VmMach_UnlockCachePage --
  3878.  *
  3879.  *      Perform machine dependent unlocking of a kernel resident page.
  3880.  *
  3881.  * Results:
  3882.  *      None.
  3883.  *
  3884.  * Side effects:
  3885.  *
  3886.  * ----------------------------------------------------------------------------
  3887.  */
  3888. /*ARGSUSED*/ 
  3889. void
  3890. VmMach_UnlockCachePage(kernelAddress)
  3891.     Address    kernelAddress;    /* Address on page to unlock. */
  3892. {
  3893.     /*
  3894.      * Sun3 leaves file cache pages always available so there is no need to
  3895.      * lock or unlock them.
  3896.      */
  3897.     return;
  3898. }
  3899.